Use new button types from lib_ui.
This commit is contained in:
		
							parent
							
								
									bc01a364d0
								
							
						
					
					
						commit
						7cfb39ea5d
					
				
					 10 changed files with 102 additions and 473 deletions
				
			
		
							
								
								
									
										
											BIN
										
									
								
								Telegram/Resources/icons/calls/call_settings.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Telegram/Resources/icons/calls/call_settings.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 345 B | 
							
								
								
									
										
											BIN
										
									
								
								Telegram/Resources/icons/calls/call_settings@2x.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Telegram/Resources/icons/calls/call_settings@2x.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 591 B | 
							
								
								
									
										
											BIN
										
									
								
								Telegram/Resources/icons/calls/call_settings@3x.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Telegram/Resources/icons/calls/call_settings@3x.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 932 B | 
|  | @ -1817,6 +1817,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| "lng_group_call_settings" = "Settings"; | "lng_group_call_settings" = "Settings"; | ||||||
| "lng_group_call_unmute" = "Unmute"; | "lng_group_call_unmute" = "Unmute"; | ||||||
| "lng_group_call_you_are_live" = "You are Live"; | "lng_group_call_you_are_live" = "You are Live"; | ||||||
|  | "lng_group_call_force_muted" = "You are muted"; | ||||||
| "lng_group_call_connecting" = "Connecting..."; | "lng_group_call_connecting" = "Connecting..."; | ||||||
| "lng_group_call_leave" = "Leave"; | "lng_group_call_leave" = "Leave"; | ||||||
| "lng_group_call_leave_title" = "Leave voice chat"; | "lng_group_call_leave_title" = "Leave voice chat"; | ||||||
|  |  | ||||||
|  | @ -120,12 +120,14 @@ callAnswer: CallButton { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	bg: callAnswerBg; | 	bg: callAnswerBg; | ||||||
|  | 	bgSize: 44px; | ||||||
|  | 	bgPosition: point(12px, 12px); | ||||||
| 	angle: 135.; | 	angle: 135.; | ||||||
| 	outerRadius: 12px; | 	outerRadius: 12px; | ||||||
| 	outerBg: callAnswerBgOuter; | 	outerBg: callAnswerBgOuter; | ||||||
| 	label: callButtonLabel; | 	label: callButtonLabel; | ||||||
| } | } | ||||||
| callHangup: CallButton { | callHangup: CallButton(callAnswer) { | ||||||
| 	button: IconButton(callButton) { | 	button: IconButton(callButton) { | ||||||
| 		icon: icon {{ "calls/call_discard", callIconFg }}; | 		icon: icon {{ "calls/call_discard", callIconFg }}; | ||||||
| 		ripple: RippleAnimation(defaultRippleAnimation) { | 		ripple: RippleAnimation(defaultRippleAnimation) { | ||||||
|  | @ -136,7 +138,7 @@ callHangup: CallButton { | ||||||
| 	outerBg: callHangupBg; | 	outerBg: callHangupBg; | ||||||
| 	label: callButtonLabel; | 	label: callButtonLabel; | ||||||
| } | } | ||||||
| callCancel: CallButton { | callCancel: CallButton(callAnswer) { | ||||||
| 	button: IconButton(callButton) { | 	button: IconButton(callButton) { | ||||||
| 		icon: icon {{ "calls/call_cancel", callIconFgActive }}; | 		icon: icon {{ "calls/call_cancel", callIconFgActive }}; | ||||||
| 		ripple: RippleAnimation(defaultRippleAnimation) { | 		ripple: RippleAnimation(defaultRippleAnimation) { | ||||||
|  | @ -147,7 +149,7 @@ callCancel: CallButton { | ||||||
| 	outerBg: callIconBgActive; | 	outerBg: callIconBgActive; | ||||||
| 	label: callButtonLabel; | 	label: callButtonLabel; | ||||||
| } | } | ||||||
| callMicrophoneMute: CallButton { | callMicrophoneMute: CallButton(callAnswer) { | ||||||
| 	button: IconButton(callButton) { | 	button: IconButton(callButton) { | ||||||
| 		icon: icon {{ "calls/call_record_active", callIconFg }}; | 		icon: icon {{ "calls/call_record_active", callIconFg }}; | ||||||
| 		ripple: RippleAnimation(defaultRippleAnimation) { | 		ripple: RippleAnimation(defaultRippleAnimation) { | ||||||
|  | @ -478,3 +480,19 @@ groupCallMutedButton: IconButton(groupCallInactiveButton) { | ||||||
| 	iconOver: icon {{ "calls/group_calls_muted", groupCallMemberMutedIcon }}; | 	iconOver: icon {{ "calls/group_calls_muted", groupCallMemberMutedIcon }}; | ||||||
| } | } | ||||||
| groupCallMemberButtonSkip: 10px; | groupCallMemberButtonSkip: 10px; | ||||||
|  | 
 | ||||||
|  | groupCallSettings: CallButton(callMicrophoneMute) { | ||||||
|  | 	button: IconButton(callButton) { | ||||||
|  | 		iconPosition: point(-1px, 22px); | ||||||
|  | 		icon: icon {{ "calls/call_settings", callIconFg }}; | ||||||
|  | 		ripple: RippleAnimation(defaultRippleAnimation) { | ||||||
|  | 			color: callMuteRipple; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	bg: callIconBg; | ||||||
|  | 	outerBg: callMuteRipple; | ||||||
|  | 	label: callButtonLabel; | ||||||
|  | } | ||||||
|  | groupCallButtonSkip: 43px; | ||||||
|  | groupCallButtonBottomSkip: 134px; | ||||||
|  | groupCallMuteBottomSkip: 149px; | ||||||
|  |  | ||||||
|  | @ -10,7 +10,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "calls/calls_group_members.h" | #include "calls/calls_group_members.h" | ||||||
| #include "ui/widgets/buttons.h" | #include "ui/widgets/buttons.h" | ||||||
| #include "ui/widgets/window.h" | #include "ui/widgets/window.h" | ||||||
| #include "ui/effects/ripple_animation.h" | #include "ui/widgets/call_button.h" | ||||||
|  | #include "ui/widgets/call_mute_button.h" | ||||||
| #include "ui/layers/layer_manager.h" | #include "ui/layers/layer_manager.h" | ||||||
| #include "boxes/confirm_box.h" | #include "boxes/confirm_box.h" | ||||||
| #include "core/application.h" | #include "core/application.h" | ||||||
|  | @ -29,191 +30,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| 
 | 
 | ||||||
| namespace Calls { | namespace Calls { | ||||||
| 
 | 
 | ||||||
| class GroupPanel::Button final : public Ui::RippleButton { |  | ||||||
| public: |  | ||||||
| 	Button( |  | ||||||
| 		QWidget *parent, |  | ||||||
| 		const style::CallButton &stFrom, |  | ||||||
| 		const style::CallButton *stTo = nullptr); |  | ||||||
| 
 |  | ||||||
| 	void setProgress(float64 progress); |  | ||||||
| 	void setText(rpl::producer<QString> text); |  | ||||||
| 
 |  | ||||||
| protected: |  | ||||||
| 	void paintEvent(QPaintEvent *e) override; |  | ||||||
| 
 |  | ||||||
| 	void onStateChanged(State was, StateChangeSource source) override; |  | ||||||
| 
 |  | ||||||
| 	QImage prepareRippleMask() const override; |  | ||||||
| 	QPoint prepareRippleStartPosition() const override; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
| 	QPoint iconPosition(not_null<const style::CallButton*> st) const; |  | ||||||
| 	void mixIconMasks(); |  | ||||||
| 
 |  | ||||||
| 	not_null<const style::CallButton*> _stFrom; |  | ||||||
| 	const style::CallButton *_stTo = nullptr; |  | ||||||
| 	float64 _progress = 0.; |  | ||||||
| 
 |  | ||||||
| 	object_ptr<Ui::FlatLabel> _label = { nullptr }; |  | ||||||
| 
 |  | ||||||
| 	QImage _bgMask, _bg; |  | ||||||
| 	QPixmap _bgFrom, _bgTo; |  | ||||||
| 	QImage _iconMixedMask, _iconFrom, _iconTo, _iconMixed; |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| GroupPanel::Button::Button( |  | ||||||
| 	QWidget *parent, |  | ||||||
| 	const style::CallButton &stFrom, |  | ||||||
| 	const style::CallButton *stTo) |  | ||||||
| : Ui::RippleButton(parent, stFrom.button.ripple) |  | ||||||
| , _stFrom(&stFrom) |  | ||||||
| , _stTo(stTo) { |  | ||||||
| 	resize(_stFrom->button.width, _stFrom->button.height); |  | ||||||
| 
 |  | ||||||
| 	_bgMask = prepareRippleMask(); |  | ||||||
| 	_bgFrom = App::pixmapFromImageInPlace(style::colorizeImage(_bgMask, _stFrom->bg)); |  | ||||||
| 	if (_stTo) { |  | ||||||
| 		Assert(_stFrom->button.width == _stTo->button.width); |  | ||||||
| 		Assert(_stFrom->button.height == _stTo->button.height); |  | ||||||
| 		Assert(_stFrom->button.rippleAreaPosition == _stTo->button.rippleAreaPosition); |  | ||||||
| 		Assert(_stFrom->button.rippleAreaSize == _stTo->button.rippleAreaSize); |  | ||||||
| 
 |  | ||||||
| 		_bg = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); |  | ||||||
| 		_bg.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 		_bgTo = App::pixmapFromImageInPlace(style::colorizeImage(_bgMask, _stTo->bg)); |  | ||||||
| 		_iconMixedMask = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); |  | ||||||
| 		_iconMixedMask.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 		_iconFrom = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); |  | ||||||
| 		_iconFrom.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 		_iconFrom.fill(Qt::black); |  | ||||||
| 		{ |  | ||||||
| 			Painter p(&_iconFrom); |  | ||||||
| 			p.drawImage((_stFrom->button.rippleAreaSize - _stFrom->button.icon.width()) / 2, (_stFrom->button.rippleAreaSize - _stFrom->button.icon.height()) / 2, _stFrom->button.icon.instance(Qt::white)); |  | ||||||
| 		} |  | ||||||
| 		_iconTo = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); |  | ||||||
| 		_iconTo.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 		_iconTo.fill(Qt::black); |  | ||||||
| 		{ |  | ||||||
| 			Painter p(&_iconTo); |  | ||||||
| 			p.drawImage((_stTo->button.rippleAreaSize - _stTo->button.icon.width()) / 2, (_stTo->button.rippleAreaSize - _stTo->button.icon.height()) / 2, _stTo->button.icon.instance(Qt::white)); |  | ||||||
| 		} |  | ||||||
| 		_iconMixed = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); |  | ||||||
| 		_iconMixed.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void GroupPanel::Button::setText(rpl::producer<QString> text) { |  | ||||||
| 	_label.create(this, std::move(text), _stFrom->label); |  | ||||||
| 	_label->show(); |  | ||||||
| 	rpl::combine( |  | ||||||
| 		sizeValue(), |  | ||||||
| 		_label->sizeValue() |  | ||||||
| 	) | rpl::start_with_next([=](QSize my, QSize label) { |  | ||||||
| 		_label->moveToLeft( |  | ||||||
| 			(my.width() - label.width()) / 2, |  | ||||||
| 			my.height() - label.height(), |  | ||||||
| 			my.width()); |  | ||||||
| 	}, _label->lifetime()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void GroupPanel::Button::setProgress(float64 progress) { |  | ||||||
| 	_progress = progress; |  | ||||||
| 	update(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void GroupPanel::Button::paintEvent(QPaintEvent *e) { |  | ||||||
| 	Painter p(this); |  | ||||||
| 
 |  | ||||||
| 	auto bgPosition = myrtlpoint(_stFrom->button.rippleAreaPosition); |  | ||||||
| 	auto paintFrom = (_progress == 0.) || !_stTo; |  | ||||||
| 	auto paintTo = !paintFrom && (_progress == 1.); |  | ||||||
| 
 |  | ||||||
| 	if (paintFrom) { |  | ||||||
| 		p.drawPixmap(bgPosition, _bgFrom); |  | ||||||
| 	} else if (paintTo) { |  | ||||||
| 		p.drawPixmap(bgPosition, _bgTo); |  | ||||||
| 	} else { |  | ||||||
| 		style::colorizeImage(_bgMask, anim::color(_stFrom->bg, _stTo->bg, _progress), &_bg); |  | ||||||
| 		p.drawImage(bgPosition, _bg); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	auto rippleColorInterpolated = QColor(); |  | ||||||
| 	auto rippleColorOverride = &rippleColorInterpolated; |  | ||||||
| 	if (paintFrom) { |  | ||||||
| 		rippleColorOverride = nullptr; |  | ||||||
| 	} else if (paintTo) { |  | ||||||
| 		rippleColorOverride = &_stTo->button.ripple.color->c; |  | ||||||
| 	} else { |  | ||||||
| 		rippleColorInterpolated = anim::color(_stFrom->button.ripple.color, _stTo->button.ripple.color, _progress); |  | ||||||
| 	} |  | ||||||
| 	paintRipple(p, _stFrom->button.rippleAreaPosition.x(), _stFrom->button.rippleAreaPosition.y(), rippleColorOverride); |  | ||||||
| 
 |  | ||||||
| 	auto positionFrom = iconPosition(_stFrom); |  | ||||||
| 	if (paintFrom) { |  | ||||||
| 		const auto icon = &_stFrom->button.icon; |  | ||||||
| 		icon->paint(p, positionFrom, width()); |  | ||||||
| 	} else { |  | ||||||
| 		auto positionTo = iconPosition(_stTo); |  | ||||||
| 		if (paintTo) { |  | ||||||
| 			_stTo->button.icon.paint(p, positionTo, width()); |  | ||||||
| 		} else { |  | ||||||
| 			mixIconMasks(); |  | ||||||
| 			style::colorizeImage(_iconMixedMask, st::callIconFg->c, &_iconMixed); |  | ||||||
| 			p.drawImage(myrtlpoint(_stFrom->button.rippleAreaPosition), _iconMixed); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QPoint GroupPanel::Button::iconPosition(not_null<const style::CallButton*> st) const { |  | ||||||
| 	auto result = st->button.iconPosition; |  | ||||||
| 	if (result.x() < 0) { |  | ||||||
| 		result.setX((width() - st->button.icon.width()) / 2); |  | ||||||
| 	} |  | ||||||
| 	if (result.y() < 0) { |  | ||||||
| 		result.setY((height() - st->button.icon.height()) / 2); |  | ||||||
| 	} |  | ||||||
| 	return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void GroupPanel::Button::mixIconMasks() { |  | ||||||
| 	_iconMixedMask.fill(Qt::black); |  | ||||||
| 
 |  | ||||||
| 	Painter p(&_iconMixedMask); |  | ||||||
| 	PainterHighQualityEnabler hq(p); |  | ||||||
| 	auto paintIconMask = [this, &p](const QImage &mask, float64 angle) { |  | ||||||
| 		auto skipFrom = _stFrom->button.rippleAreaSize / 2; |  | ||||||
| 		p.translate(skipFrom, skipFrom); |  | ||||||
| 		p.rotate(angle); |  | ||||||
| 		p.translate(-skipFrom, -skipFrom); |  | ||||||
| 		p.drawImage(0, 0, mask); |  | ||||||
| 	}; |  | ||||||
| 	p.save(); |  | ||||||
| 	paintIconMask(_iconFrom, (_stFrom->angle - _stTo->angle) * _progress); |  | ||||||
| 	p.restore(); |  | ||||||
| 	p.setOpacity(_progress); |  | ||||||
| 	paintIconMask(_iconTo, (_stTo->angle - _stFrom->angle) * (1. - _progress)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void GroupPanel::Button::onStateChanged(State was, StateChangeSource source) { |  | ||||||
| 	RippleButton::onStateChanged(was, source); |  | ||||||
| 
 |  | ||||||
| 	auto over = isOver(); |  | ||||||
| 	auto wasOver = static_cast<bool>(was & StateFlag::Over); |  | ||||||
| 	if (over != wasOver) { |  | ||||||
| 		update(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QPoint GroupPanel::Button::prepareRippleStartPosition() const { |  | ||||||
| 	return mapFromGlobal(QCursor::pos()) - _stFrom->button.rippleAreaPosition; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QImage GroupPanel::Button::prepareRippleMask() const { |  | ||||||
| 	return Ui::RippleAnimation::ellipseMask(QSize(_stFrom->button.rippleAreaSize, _stFrom->button.rippleAreaSize)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| GroupPanel::GroupPanel(not_null<GroupCall*> call) | GroupPanel::GroupPanel(not_null<GroupCall*> call) | ||||||
| : _call(call) | : _call(call) | ||||||
| , _channel(call->channel()) | , _channel(call->channel()) | ||||||
|  | @ -225,9 +41,14 @@ GroupPanel::GroupPanel(not_null<GroupCall*> call) | ||||||
| 	st::callTitle)) | 	st::callTitle)) | ||||||
| #endif // Q_OS_WIN
 | #endif // Q_OS_WIN
 | ||||||
| , _members(widget(), call) | , _members(widget(), call) | ||||||
| , _settings(widget(), st::callCancel) | , _settings(widget(), st::groupCallSettings) | ||||||
| , _hangup(widget(), st::callHangup) | , _mute(std::make_unique<Ui::CallMuteButton>( | ||||||
| , _mute(widget(), st::callMicrophoneMute, &st::callMicrophoneUnmute) { | 	widget(), | ||||||
|  | 	Ui::CallMuteButtonState{ | ||||||
|  | 		.text = tr::lng_group_call_connecting(tr::now), | ||||||
|  | 		.type = Ui::CallMuteButtonType::Connecting, | ||||||
|  | 	})) | ||||||
|  | , _hangup(widget(), st::callHangup) { | ||||||
| 	initWindow(); | 	initWindow(); | ||||||
| 	initWidget(); | 	initWidget(); | ||||||
| 	initControls(); | 	initControls(); | ||||||
|  | @ -297,22 +118,17 @@ void GroupPanel::initWidget() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GroupPanel::initControls() { | void GroupPanel::initControls() { | ||||||
| 	_call->mutedValue( | 	_mute->clicks( | ||||||
| 	) | rpl::start_with_next([=](MuteState state) { | 	) | rpl::filter([=](Qt::MouseButton button) { | ||||||
| 		if (state == MuteState::ForceMuted) { | 		return (button == Qt::LeftButton); | ||||||
| 			_mute->clearState(); | 	}) | rpl::start_with_next([=] { | ||||||
| 		} |  | ||||||
| 		_mute->setAttribute( |  | ||||||
| 			Qt::WA_TransparentForMouseEvents, |  | ||||||
| 			(state == MuteState::ForceMuted)); |  | ||||||
| 	}, _mute->lifetime()); |  | ||||||
| 	_mute->setClickedCallback([=] { |  | ||||||
| 		if (_call && _call->muted() != MuteState::ForceMuted) { | 		if (_call && _call->muted() != MuteState::ForceMuted) { | ||||||
| 			_call->setMuted((_call->muted() == MuteState::Active) | 			_call->setMuted((_call->muted() == MuteState::Active) | ||||||
| 				? MuteState::Muted | 				? MuteState::Muted | ||||||
| 				: MuteState::Active); | 				: MuteState::Active); | ||||||
| 		} | 		} | ||||||
| 	}); | 	}, _mute->lifetime()); | ||||||
|  | 
 | ||||||
| 	_hangup->setClickedCallback([=] { | 	_hangup->setClickedCallback([=] { | ||||||
| 		_layerBg->showBox(Box<ConfirmBox>( | 		_layerBg->showBox(Box<ConfirmBox>( | ||||||
| 			tr::lng_group_call_leave_sure(tr::now), | 			tr::lng_group_call_leave_sure(tr::now), | ||||||
|  | @ -321,6 +137,15 @@ void GroupPanel::initControls() { | ||||||
| 	}); | 	}); | ||||||
| 	_settings->setClickedCallback([=] { | 	_settings->setClickedCallback([=] { | ||||||
| 	}); | 	}); | ||||||
|  | 
 | ||||||
|  | 	_settings->setText(tr::lng_menu_settings()); | ||||||
|  | 	_hangup->setText(tr::lng_box_leave()); | ||||||
|  | 
 | ||||||
|  | 	_members->desiredHeightValue( | ||||||
|  | 	) | rpl::start_with_next([=] { | ||||||
|  | 		updateControlsGeometry(); | ||||||
|  | 	}, _members->lifetime()); | ||||||
|  | 
 | ||||||
| 	initWithCall(_call); | 	initWithCall(_call); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -333,33 +158,44 @@ void GroupPanel::initWithCall(GroupCall *call) { | ||||||
| 
 | 
 | ||||||
| 	_channel = _call->channel(); | 	_channel = _call->channel(); | ||||||
| 
 | 
 | ||||||
| 	_settings->setText(tr::lng_menu_settings()); | 	call->levelUpdates( | ||||||
| 	_hangup->setText(tr::lng_box_leave()); | 	) | rpl::filter([=](const LevelUpdate &update) { | ||||||
| 
 | 		return update.self; | ||||||
| 	_call->mutedValue( | 	}) | rpl::start_with_next([=](const LevelUpdate &update) { | ||||||
| 	) | rpl::start_with_next([=](MuteState state) { | 		_mute->setLevel(update.value); | ||||||
| 		_mute->setProgress((state != MuteState::Active) ? 1. : 0.); |  | ||||||
| 		_mute->setText((state != MuteState::Active) |  | ||||||
| 			? tr::lng_call_unmute_audio() |  | ||||||
| 			: tr::lng_call_mute_audio()); |  | ||||||
| 	}, _callLifetime); | 	}, _callLifetime); | ||||||
| 
 | 
 | ||||||
| 	_call->stateValue( |  | ||||||
| 	) | rpl::start_with_next([=](State state) { |  | ||||||
| 		stateChanged(state); |  | ||||||
| 	}, _callLifetime); |  | ||||||
| 
 |  | ||||||
| 	_members->desiredHeightValue( |  | ||||||
| 	) | rpl::start_with_next([=] { |  | ||||||
| 		updateControlsGeometry(); |  | ||||||
| 	}, _members->lifetime()); |  | ||||||
| 
 |  | ||||||
| 	_members->toggleMuteRequests( | 	_members->toggleMuteRequests( | ||||||
| 	) | rpl::start_with_next([=](GroupMembers::MuteRequest request) { | 	) | rpl::start_with_next([=](GroupMembers::MuteRequest request) { | ||||||
| 		if (_call) { | 		if (_call) { | ||||||
| 			_call->toggleMute(request.user, request.mute); | 			_call->toggleMute(request.user, request.mute); | ||||||
| 		} | 		} | ||||||
| 	}, _callLifetime); | 	}, _callLifetime); | ||||||
|  | 
 | ||||||
|  | 	using namespace rpl::mappers; | ||||||
|  | 	rpl::combine( | ||||||
|  | 		_call->mutedValue(), | ||||||
|  | 		_call->stateValue() | rpl::map( | ||||||
|  | 			_1 == State::Creating || _1 == State::Joining | ||||||
|  | 		) | ||||||
|  | 	) | rpl::start_with_next([=](MuteState mute, bool connecting) { | ||||||
|  | 		_mute->setState(Ui::CallMuteButtonState{ | ||||||
|  | 			.text = (connecting | ||||||
|  | 				? tr::lng_group_call_connecting(tr::now) | ||||||
|  | 				: mute == MuteState::ForceMuted | ||||||
|  | 				? tr::lng_group_call_force_muted(tr::now) | ||||||
|  | 				: mute != MuteState::Active | ||||||
|  | 				? tr::lng_call_unmute_audio(tr::now) | ||||||
|  | 				: tr::lng_call_mute_audio(tr::now)), | ||||||
|  | 			.type = (connecting | ||||||
|  | 				? Ui::CallMuteButtonType::Connecting | ||||||
|  | 				: mute == MuteState::ForceMuted | ||||||
|  | 				? Ui::CallMuteButtonType::ForceMuted | ||||||
|  | 				: mute == MuteState::Muted | ||||||
|  | 				? Ui::CallMuteButtonType::Muted | ||||||
|  | 				: Ui::CallMuteButtonType::Active), | ||||||
|  | 		}); | ||||||
|  | 	}, _callLifetime); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GroupPanel::initLayout() { | void GroupPanel::initLayout() { | ||||||
|  | @ -424,10 +260,10 @@ void GroupPanel::updateControlsGeometry() { | ||||||
| 		membersWidthAvailable, | 		membersWidthAvailable, | ||||||
| 		membersWidthMin, | 		membersWidthMin, | ||||||
| 		st::groupCallMembersWidthMax); | 		st::groupCallMembersWidthMax); | ||||||
| 	const auto muteTop = widget()->height() - 2 * _mute->height(); | 	const auto muteTop = widget()->height() - st::groupCallMuteBottomSkip; | ||||||
| 	const auto buttonsTop = muteTop; | 	const auto buttonsTop = widget()->height() - st::groupCallButtonBottomSkip; | ||||||
| 	const auto membersTop = computeMembersListTop(); | 	const auto membersTop = computeMembersListTop(); | ||||||
| 	const auto availableHeight = buttonsTop | 	const auto availableHeight = muteTop | ||||||
| 		- membersTop | 		- membersTop | ||||||
| 		- st::groupCallMembersMargin.bottom(); | 		- st::groupCallMembersMargin.bottom(); | ||||||
| 	_members->setGeometry( | 	_members->setGeometry( | ||||||
|  | @ -435,9 +271,13 @@ void GroupPanel::updateControlsGeometry() { | ||||||
| 		membersTop, | 		membersTop, | ||||||
| 		membersWidth, | 		membersWidth, | ||||||
| 		std::min(desiredHeight, availableHeight)); | 		std::min(desiredHeight, availableHeight)); | ||||||
| 	_mute->move((widget()->width() - _mute->width()) / 2, muteTop); | 	const auto muteSize = _mute->innerSize().width(); | ||||||
| 	_settings->moveToLeft(_settings->width(), buttonsTop); | 	const auto fullWidth = muteSize | ||||||
| 	_hangup->moveToRight(_settings->width(), buttonsTop); | 		+ 2 * _settings->width() | ||||||
|  | 		+ 2 * st::groupCallButtonSkip; | ||||||
|  | 	_mute->moveInner({ (widget()->width() - muteSize) / 2, muteTop }); | ||||||
|  | 	_settings->moveToLeft((widget()->width() - fullWidth) / 2, buttonsTop); | ||||||
|  | 	_hangup->moveToRight((widget()->width() - fullWidth) / 2, buttonsTop); | ||||||
| 	refreshTitle(); | 	refreshTitle(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -495,14 +335,4 @@ not_null<Ui::RpWidget*> GroupPanel::widget() const { | ||||||
| 	return _window->body(); | 	return _window->body(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GroupPanel::stateChanged(State state) { |  | ||||||
| 	Expects(_call != nullptr); |  | ||||||
| 
 |  | ||||||
| 	if ((state != State::HangingUp) |  | ||||||
| 		&& (state != State::Ended) |  | ||||||
| 		&& (state != State::FailedHangingUp) |  | ||||||
| 		&& (state != State::Failed)) { |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| } // namespace Calls
 | } // namespace Calls
 | ||||||
|  |  | ||||||
|  | @ -22,6 +22,8 @@ class CloudImageView; | ||||||
| } // namespace Data
 | } // namespace Data
 | ||||||
| 
 | 
 | ||||||
| namespace Ui { | namespace Ui { | ||||||
|  | class CallButton; | ||||||
|  | class CallMuteButton; | ||||||
| class IconButton; | class IconButton; | ||||||
| class FlatLabel; | class FlatLabel; | ||||||
| template <typename Widget> | template <typename Widget> | ||||||
|  | @ -57,7 +59,6 @@ public: | ||||||
| 	void closeBeforeDestroy(); | 	void closeBeforeDestroy(); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	class Button; |  | ||||||
| 	using State = GroupCall::State; | 	using State = GroupCall::State; | ||||||
| 
 | 
 | ||||||
| 	[[nodiscard]] not_null<Ui::RpWidget*> widget() const; | 	[[nodiscard]] not_null<Ui::RpWidget*> widget() const; | ||||||
|  | @ -74,7 +75,6 @@ private: | ||||||
| 	bool handleClose(); | 	bool handleClose(); | ||||||
| 
 | 
 | ||||||
| 	void updateControlsGeometry(); | 	void updateControlsGeometry(); | ||||||
| 	void stateChanged(State state); |  | ||||||
| 	void showControls(); | 	void showControls(); | ||||||
| 
 | 
 | ||||||
| 	[[nodiscard]] int computeMembersListTop() const; | 	[[nodiscard]] int computeMembersListTop() const; | ||||||
|  | @ -96,9 +96,9 @@ private: | ||||||
| 	object_ptr<Ui::FlatLabel> _title = { nullptr }; | 	object_ptr<Ui::FlatLabel> _title = { nullptr }; | ||||||
| 	object_ptr<GroupMembers> _members; | 	object_ptr<GroupMembers> _members; | ||||||
| 
 | 
 | ||||||
| 	object_ptr<Button> _settings; | 	object_ptr<Ui::CallButton> _settings; | ||||||
| 	object_ptr<Button> _hangup; | 	std::unique_ptr<Ui::CallMuteButton> _mute; | ||||||
| 	object_ptr<Button> _mute; | 	object_ptr<Ui::CallButton> _hangup; | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -18,11 +18,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL | ||||||
| #include "calls/calls_signal_bars.h" | #include "calls/calls_signal_bars.h" | ||||||
| #include "calls/calls_userpic.h" | #include "calls/calls_userpic.h" | ||||||
| #include "calls/calls_video_bubble.h" | #include "calls/calls_video_bubble.h" | ||||||
|  | #include "ui/widgets/call_button.h" | ||||||
| #include "ui/widgets/buttons.h" | #include "ui/widgets/buttons.h" | ||||||
| #include "ui/widgets/labels.h" | #include "ui/widgets/labels.h" | ||||||
| #include "ui/widgets/shadow.h" | #include "ui/widgets/shadow.h" | ||||||
| #include "ui/widgets/window.h" | #include "ui/widgets/window.h" | ||||||
| #include "ui/effects/ripple_animation.h" |  | ||||||
| #include "ui/image/image.h" | #include "ui/image/image.h" | ||||||
| #include "ui/text/format_values.h" | #include "ui/text/format_values.h" | ||||||
| #include "ui/wrap/fade_wrap.h" | #include "ui/wrap/fade_wrap.h" | ||||||
|  | @ -170,226 +170,6 @@ void Panel::Incoming::fillBottomShadow(QPainter &p) { | ||||||
| 			factor * fill.height())); | 			factor * fill.height())); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| class Panel::Button final : public Ui::RippleButton { |  | ||||||
| public: |  | ||||||
| 	Button( |  | ||||||
| 		QWidget *parent, |  | ||||||
| 		const style::CallButton &stFrom, |  | ||||||
| 		const style::CallButton *stTo = nullptr); |  | ||||||
| 
 |  | ||||||
| 	void setProgress(float64 progress); |  | ||||||
| 	void setOuterValue(float64 value); |  | ||||||
| 	void setText(rpl::producer<QString> text); |  | ||||||
| 
 |  | ||||||
| protected: |  | ||||||
| 	void paintEvent(QPaintEvent *e) override; |  | ||||||
| 
 |  | ||||||
| 	void onStateChanged(State was, StateChangeSource source) override; |  | ||||||
| 
 |  | ||||||
| 	QImage prepareRippleMask() const override; |  | ||||||
| 	QPoint prepareRippleStartPosition() const override; |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
| 	QPoint iconPosition(not_null<const style::CallButton*> st) const; |  | ||||||
| 	void mixIconMasks(); |  | ||||||
| 
 |  | ||||||
| 	not_null<const style::CallButton*> _stFrom; |  | ||||||
| 	const style::CallButton *_stTo = nullptr; |  | ||||||
| 	float64 _progress = 0.; |  | ||||||
| 
 |  | ||||||
| 	object_ptr<Ui::FlatLabel> _label = { nullptr }; |  | ||||||
| 
 |  | ||||||
| 	QImage _bgMask, _bg; |  | ||||||
| 	QPixmap _bgFrom, _bgTo; |  | ||||||
| 	QImage _iconMixedMask, _iconFrom, _iconTo, _iconMixed; |  | ||||||
| 
 |  | ||||||
| 	float64 _outerValue = 0.; |  | ||||||
| 	Ui::Animations::Simple _outerAnimation; |  | ||||||
| 
 |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| Panel::Button::Button( |  | ||||||
| 	QWidget *parent, |  | ||||||
| 	const style::CallButton &stFrom, |  | ||||||
| 	const style::CallButton *stTo) |  | ||||||
| : Ui::RippleButton(parent, stFrom.button.ripple) |  | ||||||
| , _stFrom(&stFrom) |  | ||||||
| , _stTo(stTo) { |  | ||||||
| 	resize(_stFrom->button.width, _stFrom->button.height); |  | ||||||
| 
 |  | ||||||
| 	_bgMask = prepareRippleMask(); |  | ||||||
| 	_bgFrom = App::pixmapFromImageInPlace(style::colorizeImage(_bgMask, _stFrom->bg)); |  | ||||||
| 	if (_stTo) { |  | ||||||
| 		Assert(_stFrom->button.width == _stTo->button.width); |  | ||||||
| 		Assert(_stFrom->button.height == _stTo->button.height); |  | ||||||
| 		Assert(_stFrom->button.rippleAreaPosition == _stTo->button.rippleAreaPosition); |  | ||||||
| 		Assert(_stFrom->button.rippleAreaSize == _stTo->button.rippleAreaSize); |  | ||||||
| 
 |  | ||||||
| 		_bg = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); |  | ||||||
| 		_bg.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 		_bgTo = App::pixmapFromImageInPlace(style::colorizeImage(_bgMask, _stTo->bg)); |  | ||||||
| 		_iconMixedMask = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); |  | ||||||
| 		_iconMixedMask.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 		_iconFrom = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); |  | ||||||
| 		_iconFrom.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 		_iconFrom.fill(Qt::black); |  | ||||||
| 		{ |  | ||||||
| 			Painter p(&_iconFrom); |  | ||||||
| 			p.drawImage((_stFrom->button.rippleAreaSize - _stFrom->button.icon.width()) / 2, (_stFrom->button.rippleAreaSize - _stFrom->button.icon.height()) / 2, _stFrom->button.icon.instance(Qt::white)); |  | ||||||
| 		} |  | ||||||
| 		_iconTo = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); |  | ||||||
| 		_iconTo.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 		_iconTo.fill(Qt::black); |  | ||||||
| 		{ |  | ||||||
| 			Painter p(&_iconTo); |  | ||||||
| 			p.drawImage((_stTo->button.rippleAreaSize - _stTo->button.icon.width()) / 2, (_stTo->button.rippleAreaSize - _stTo->button.icon.height()) / 2, _stTo->button.icon.instance(Qt::white)); |  | ||||||
| 		} |  | ||||||
| 		_iconMixed = QImage(_bgMask.size(), QImage::Format_ARGB32_Premultiplied); |  | ||||||
| 		_iconMixed.setDevicePixelRatio(cRetinaFactor()); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Panel::Button::setOuterValue(float64 value) { |  | ||||||
| 	if (_outerValue != value) { |  | ||||||
| 		_outerAnimation.start([this] { |  | ||||||
| 			if (_progress == 0. || _progress == 1.) { |  | ||||||
| 				update(); |  | ||||||
| 			} |  | ||||||
| 		}, _outerValue, value, Call::kSoundSampleMs); |  | ||||||
| 		_outerValue = value; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Panel::Button::setText(rpl::producer<QString> text) { |  | ||||||
| 	_label.create(this, std::move(text), _stFrom->label); |  | ||||||
| 	_label->show(); |  | ||||||
| 	rpl::combine( |  | ||||||
| 		sizeValue(), |  | ||||||
| 		_label->sizeValue() |  | ||||||
| 	) | rpl::start_with_next([=](QSize my, QSize label) { |  | ||||||
| 		_label->moveToLeft( |  | ||||||
| 			(my.width() - label.width()) / 2, |  | ||||||
| 			my.height() - label.height(), |  | ||||||
| 			my.width()); |  | ||||||
| 	}, _label->lifetime()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Panel::Button::setProgress(float64 progress) { |  | ||||||
| 	_progress = progress; |  | ||||||
| 	update(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Panel::Button::paintEvent(QPaintEvent *e) { |  | ||||||
| 	Painter p(this); |  | ||||||
| 
 |  | ||||||
| 	auto bgPosition = myrtlpoint(_stFrom->button.rippleAreaPosition); |  | ||||||
| 	auto paintFrom = (_progress == 0.) || !_stTo; |  | ||||||
| 	auto paintTo = !paintFrom && (_progress == 1.); |  | ||||||
| 
 |  | ||||||
| 	auto outerValue = _outerAnimation.value(_outerValue); |  | ||||||
| 	if (outerValue > 0.) { |  | ||||||
| 		auto outerRadius = paintFrom ? _stFrom->outerRadius : paintTo ? _stTo->outerRadius : (_stFrom->outerRadius * (1. - _progress) + _stTo->outerRadius * _progress); |  | ||||||
| 		auto outerPixels = outerValue * outerRadius; |  | ||||||
| 		auto outerRect = QRectF(myrtlrect(bgPosition.x(), bgPosition.y(), _stFrom->button.rippleAreaSize, _stFrom->button.rippleAreaSize)); |  | ||||||
| 		outerRect = outerRect.marginsAdded(QMarginsF(outerPixels, outerPixels, outerPixels, outerPixels)); |  | ||||||
| 
 |  | ||||||
| 		PainterHighQualityEnabler hq(p); |  | ||||||
| 		if (paintFrom) { |  | ||||||
| 			p.setBrush(_stFrom->outerBg); |  | ||||||
| 		} else if (paintTo) { |  | ||||||
| 			p.setBrush(_stTo->outerBg); |  | ||||||
| 		} else { |  | ||||||
| 			p.setBrush(anim::brush(_stFrom->outerBg, _stTo->outerBg, _progress)); |  | ||||||
| 		} |  | ||||||
| 		p.setPen(Qt::NoPen); |  | ||||||
| 		p.drawEllipse(outerRect); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (paintFrom) { |  | ||||||
| 		p.drawPixmap(bgPosition, _bgFrom); |  | ||||||
| 	} else if (paintTo) { |  | ||||||
| 		p.drawPixmap(bgPosition, _bgTo); |  | ||||||
| 	} else { |  | ||||||
| 		style::colorizeImage(_bgMask, anim::color(_stFrom->bg, _stTo->bg, _progress), &_bg); |  | ||||||
| 		p.drawImage(bgPosition, _bg); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	auto rippleColorInterpolated = QColor(); |  | ||||||
| 	auto rippleColorOverride = &rippleColorInterpolated; |  | ||||||
| 	if (paintFrom) { |  | ||||||
| 		rippleColorOverride = nullptr; |  | ||||||
| 	} else if (paintTo) { |  | ||||||
| 		rippleColorOverride = &_stTo->button.ripple.color->c; |  | ||||||
| 	} else { |  | ||||||
| 		rippleColorInterpolated = anim::color(_stFrom->button.ripple.color, _stTo->button.ripple.color, _progress); |  | ||||||
| 	} |  | ||||||
| 	paintRipple(p, _stFrom->button.rippleAreaPosition.x(), _stFrom->button.rippleAreaPosition.y(), rippleColorOverride); |  | ||||||
| 
 |  | ||||||
| 	auto positionFrom = iconPosition(_stFrom); |  | ||||||
| 	if (paintFrom) { |  | ||||||
| 		const auto icon = &_stFrom->button.icon; |  | ||||||
| 		icon->paint(p, positionFrom, width()); |  | ||||||
| 	} else { |  | ||||||
| 		auto positionTo = iconPosition(_stTo); |  | ||||||
| 		if (paintTo) { |  | ||||||
| 			_stTo->button.icon.paint(p, positionTo, width()); |  | ||||||
| 		} else { |  | ||||||
| 			mixIconMasks(); |  | ||||||
| 			style::colorizeImage(_iconMixedMask, st::callIconFg->c, &_iconMixed); |  | ||||||
| 			p.drawImage(myrtlpoint(_stFrom->button.rippleAreaPosition), _iconMixed); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QPoint Panel::Button::iconPosition(not_null<const style::CallButton*> st) const { |  | ||||||
| 	auto result = st->button.iconPosition; |  | ||||||
| 	if (result.x() < 0) { |  | ||||||
| 		result.setX((width() - st->button.icon.width()) / 2); |  | ||||||
| 	} |  | ||||||
| 	if (result.y() < 0) { |  | ||||||
| 		result.setY((height() - st->button.icon.height()) / 2); |  | ||||||
| 	} |  | ||||||
| 	return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Panel::Button::mixIconMasks() { |  | ||||||
| 	_iconMixedMask.fill(Qt::black); |  | ||||||
| 
 |  | ||||||
| 	Painter p(&_iconMixedMask); |  | ||||||
| 	PainterHighQualityEnabler hq(p); |  | ||||||
| 	auto paintIconMask = [this, &p](const QImage &mask, float64 angle) { |  | ||||||
| 		auto skipFrom = _stFrom->button.rippleAreaSize / 2; |  | ||||||
| 		p.translate(skipFrom, skipFrom); |  | ||||||
| 		p.rotate(angle); |  | ||||||
| 		p.translate(-skipFrom, -skipFrom); |  | ||||||
| 		p.drawImage(0, 0, mask); |  | ||||||
| 	}; |  | ||||||
| 	p.save(); |  | ||||||
| 	paintIconMask(_iconFrom, (_stFrom->angle - _stTo->angle) * _progress); |  | ||||||
| 	p.restore(); |  | ||||||
| 	p.setOpacity(_progress); |  | ||||||
| 	paintIconMask(_iconTo, (_stTo->angle - _stFrom->angle) * (1. - _progress)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void Panel::Button::onStateChanged(State was, StateChangeSource source) { |  | ||||||
| 	RippleButton::onStateChanged(was, source); |  | ||||||
| 
 |  | ||||||
| 	auto over = isOver(); |  | ||||||
| 	auto wasOver = static_cast<bool>(was & StateFlag::Over); |  | ||||||
| 	if (over != wasOver) { |  | ||||||
| 		update(); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QPoint Panel::Button::prepareRippleStartPosition() const { |  | ||||||
| 	return mapFromGlobal(QCursor::pos()) - _stFrom->button.rippleAreaPosition; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| QImage Panel::Button::prepareRippleMask() const { |  | ||||||
| 	return Ui::RippleAnimation::ellipseMask(QSize(_stFrom->button.rippleAreaSize, _stFrom->button.rippleAreaSize)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Panel::Panel(not_null<Call*> call) | Panel::Panel(not_null<Call*> call) | ||||||
| : _call(call) | : _call(call) | ||||||
| , _user(call->user()) | , _user(call->user()) | ||||||
|  | @ -402,8 +182,8 @@ Panel::Panel(not_null<Call*> call) | ||||||
| #endif // Q_OS_WIN
 | #endif // Q_OS_WIN
 | ||||||
| , _bodySt(&st::callBodyLayout) | , _bodySt(&st::callBodyLayout) | ||||||
| , _answerHangupRedial(widget(), st::callAnswer, &st::callHangup) | , _answerHangupRedial(widget(), st::callAnswer, &st::callHangup) | ||||||
| , _decline(widget(), object_ptr<Button>(widget(), st::callHangup)) | , _decline(widget(), object_ptr<Ui::CallButton>(widget(), st::callHangup)) | ||||||
| , _cancel(widget(), object_ptr<Button>(widget(), st::callCancel)) | , _cancel(widget(), object_ptr<Ui::CallButton>(widget(), st::callCancel)) | ||||||
| , _camera(widget(), st::callCameraMute, &st::callCameraUnmute) | , _camera(widget(), st::callCameraMute, &st::callCameraUnmute) | ||||||
| , _mute(widget(), st::callMicrophoneMute, &st::callMicrophoneUnmute) | , _mute(widget(), st::callMicrophoneMute, &st::callMicrophoneUnmute) | ||||||
| , _name(widget(), st::callName) | , _name(widget(), st::callName) | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ class CloudImageView; | ||||||
| 
 | 
 | ||||||
| namespace Ui { | namespace Ui { | ||||||
| class IconButton; | class IconButton; | ||||||
|  | class CallButton; | ||||||
| class FlatLabel; | class FlatLabel; | ||||||
| template <typename Widget> | template <typename Widget> | ||||||
| class FadeWrap; | class FadeWrap; | ||||||
|  | @ -56,7 +57,6 @@ public: | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	class Incoming; | 	class Incoming; | ||||||
| 	class Button; |  | ||||||
| 	using State = Call::State; | 	using State = Call::State; | ||||||
| 	using Type = Call::Type; | 	using Type = Call::Type; | ||||||
| 	enum class AnswerHangupRedialState : uchar { | 	enum class AnswerHangupRedialState : uchar { | ||||||
|  | @ -115,15 +115,15 @@ private: | ||||||
| 	rpl::lifetime _callLifetime; | 	rpl::lifetime _callLifetime; | ||||||
| 
 | 
 | ||||||
| 	not_null<const style::CallBodyLayout*> _bodySt; | 	not_null<const style::CallBodyLayout*> _bodySt; | ||||||
| 	object_ptr<Button> _answerHangupRedial; | 	object_ptr<Ui::CallButton> _answerHangupRedial; | ||||||
| 	object_ptr<Ui::FadeWrap<Button>> _decline; | 	object_ptr<Ui::FadeWrap<Ui::CallButton>> _decline; | ||||||
| 	object_ptr<Ui::FadeWrap<Button>> _cancel; | 	object_ptr<Ui::FadeWrap<Ui::CallButton>> _cancel; | ||||||
| 	bool _hangupShown = false; | 	bool _hangupShown = false; | ||||||
| 	bool _outgoingPreviewInBody = false; | 	bool _outgoingPreviewInBody = false; | ||||||
| 	std::optional<AnswerHangupRedialState> _answerHangupRedialState; | 	std::optional<AnswerHangupRedialState> _answerHangupRedialState; | ||||||
| 	Ui::Animations::Simple _hangupShownProgress; | 	Ui::Animations::Simple _hangupShownProgress; | ||||||
| 	object_ptr<Button> _camera; | 	object_ptr<Ui::CallButton> _camera; | ||||||
| 	object_ptr<Button> _mute; | 	object_ptr<Ui::CallButton> _mute; | ||||||
| 	object_ptr<Ui::FlatLabel> _name; | 	object_ptr<Ui::FlatLabel> _name; | ||||||
| 	object_ptr<Ui::FlatLabel> _status; | 	object_ptr<Ui::FlatLabel> _status; | ||||||
| 	object_ptr<Ui::RpWidget> _fingerprint = { nullptr }; | 	object_ptr<Ui::RpWidget> _fingerprint = { nullptr }; | ||||||
|  |  | ||||||
|  | @ -1 +1 @@ | ||||||
| Subproject commit e73bae12e26811f70adff5adfafbdb2548e02cd0 | Subproject commit 962c8d89e52a8c92bc7987eba4cfaef77a3a9ebf | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 John Preston
						John Preston