diff --git a/Telegram/Resources/icons/calls/calls_present.png b/Telegram/Resources/icons/calls/calls_present.png new file mode 100644 index 000000000..5e0ba0950 Binary files /dev/null and b/Telegram/Resources/icons/calls/calls_present.png differ diff --git a/Telegram/Resources/icons/calls/calls_present@2x.png b/Telegram/Resources/icons/calls/calls_present@2x.png new file mode 100644 index 000000000..5950f1678 Binary files /dev/null and b/Telegram/Resources/icons/calls/calls_present@2x.png differ diff --git a/Telegram/Resources/icons/calls/calls_present@3x.png b/Telegram/Resources/icons/calls/calls_present@3x.png new file mode 100644 index 000000000..ae36d18bd Binary files /dev/null and b/Telegram/Resources/icons/calls/calls_present@3x.png differ diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 051901579..ac5d5e130 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1998,6 +1998,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_group_call_raised_hand_status" = "wants to speak"; "lng_group_call_settings" = "Settings"; "lng_group_call_share_button" = "Share"; +"lng_group_call_video" = "Video"; "lng_group_call_screen_share" = "Share"; "lng_group_call_unmute_small" = "Unmute"; "lng_group_call_you_are_live_small" = "Mute"; diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index a617e585e..b0ad45ca9 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -200,7 +200,7 @@ callMuteButtonActiveInner: IconButton { } callMuteButtonSmallActiveInner: IconButton { width: 68px; - height: 79px; + height: 76px; } callMuteButtonActive: CallButton { button: callMuteButtonActiveInner; @@ -289,55 +289,6 @@ callRemoteAudioMute: FlatLabel(callStatus) { } callRemoteAudioMuteSkip: 12px; -callMuteMainBlobMinRadius: 57px; -callMuteMainBlobMaxRadius: 63px; -callMuteMinorBlobMinRadius: 64px; -callMuteMinorBlobMaxRadius: 74px; -callMuteMajorBlobMinRadius: 67px; -callMuteMajorBlobMaxRadius: 77px; - -callMuteButtonActiveInner: IconButton { - width: 136px; - height: 165px; -} -callMuteButtonLabel: FlatLabel(defaultFlatLabel) { - textFg: groupCallMembersFg; - style: TextStyle(defaultTextStyle) { - font: font(14px); - linkFont: font(14px); - linkFontOver: font(14px underline); - } -} -callMuteButtonSublabel: FlatLabel(defaultFlatLabel) { - textFg: groupCallMemberNotJoinedStatus; -} -callMuteButtonLabelsSkip: 5px; -callMuteButtonSublabelSkip: 19px; -callMuteButtonActive: CallButton { - button: callMuteButtonActiveInner; - bg: groupCallLive1; - bgSize: 100px; - bgPosition: point(18px, 18px); - outerRadius: 18px; - outerBg: callAnswerBgOuter; - label: callMuteButtonLabel; -} -callMuteButtonMuted: CallButton(callMuteButtonActive) { - bg: groupCallMuted1; - label: callMuteButtonLabel; -} -callMuteButtonConnecting: CallButton(callMuteButtonMuted) { - bg: callIconBg; - label: callMuteButtonLabel; -} -callMuteButtonLabelAdditional: 5px; - -callConnectingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) { - color: lightButtonFg; - thickness: 4px; - size: size(100px, 100px); -} - callBarHeight: 38px; callBarMuteToggle: IconButton { width: 41px; @@ -820,27 +771,67 @@ groupCallSettingsInner: IconButton(callButton) { color: callMuteRipple; } } +groupCallShareInner: IconButton(groupCallSettingsInner) { + icon: icon {{ "calls/group_calls_share", groupCallIconFg }}; +} +groupCallHangupInner: IconButton(callButton) { + icon: icon {{ "calls/call_discard", groupCallIconFg }}; + ripple: RippleAnimation(defaultRippleAnimation) { + color: groupCallLeaveBgRipple; + } +} groupCallSettings: CallButton(callMicrophoneMute) { button: groupCallSettingsInner; } groupCallShare: CallButton(groupCallSettings) { - button: IconButton(groupCallSettingsInner) { - icon: icon {{ "calls/group_calls_share", groupCallIconFg }}; - } + button: groupCallShareInner; } groupCallHangup: CallButton(callHangup) { - button: IconButton(callButton) { - icon: icon {{ "calls/call_discard", groupCallIconFg }}; - ripple: RippleAnimation(defaultRippleAnimation) { - color: groupCallLeaveBgRipple; - } - } + button: groupCallHangupInner; bg: groupCallLeaveBg; outerBg: groupCallLeaveBg; label: callButtonLabel; } +groupCallSettingsSmall: CallButton(groupCallSettings) { + button: IconButton(groupCallSettingsInner) { + height: 76px; + } +} +groupCallShareSmall: CallButton(groupCallShare) { + button: IconButton(groupCallShareInner) { + height: 76px; + } +} +groupCallHangupSmall: CallButton(groupCallHangup) { + button: IconButton(groupCallHangupInner) { + height: 76px; + } +} +groupCallVideoSmallInner: IconButton(groupCallSettingsInner) { + icon: icon {{ "calls/call_camera_muted", groupCallIconFg }}; + iconPosition: point(-1px, 16px); + ripple: RippleAnimation(defaultRippleAnimation) { + color: groupCallLeaveBgRipple; + } + height: 76px; +} +groupCallVideoSmall: CallButton(groupCallShareSmall) { + button: groupCallVideoSmallInner; +} +groupCallVideoActiveSmall: CallButton(groupCallVideoSmall) { + button: IconButton(groupCallVideoSmallInner) { + icon: icon {{ "calls/call_camera_active", groupCallIconFg }}; + } +} +groupCallScreenShareSmall: CallButton(groupCallShareSmall) { + button: IconButton(groupCallSettingsInner) { + icon: icon {{ "calls/calls_present", groupCallIconFg }}; + } +} groupCallButtonSkip: 43px; +groupCallButtonSkipSmall: 4px; groupCallButtonBottomSkip: 145px; +groupCallButtonBottomSkipSmall: 95px; groupCallMuteBottomSkip: 160px; groupCallTopBarUserpics: GroupCallUserpics { diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.cpp b/Telegram/SourceFiles/calls/group/calls_group_call.cpp index 597842983..190b574ac 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_call.cpp @@ -405,15 +405,24 @@ bool GroupCall::isScreenSharing() const { return (_videoDeviceId != _videoInputId); } -void GroupCall::switchToCamera() { - if (!_videoCapture || !isScreenSharing()) { +void GroupCall::toggleVideo(bool active) { + if (!active) { + if (!isScreenSharing()) { + _videoOutgoing->setState(Webrtc::VideoState::Inactive); + } return; } + const auto changing = isScreenSharing(); _videoDeviceId = _videoInputId; if (_videoOutgoing->state() != Webrtc::VideoState::Active) { _videoOutgoing->setState(Webrtc::VideoState::Active); } - _videoCapture->switchToDevice(_videoDeviceId.toStdString()); + if (!_videoCapture) { + return; + } + if (changing) { + _videoCapture->switchToDevice(_videoDeviceId.toStdString()); + } } void GroupCall::switchToScreenSharing(const QString &uniqueId) { diff --git a/Telegram/SourceFiles/calls/group/calls_group_call.h b/Telegram/SourceFiles/calls/group/calls_group_call.h index a6773aa61..fb5e6cd17 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_call.h +++ b/Telegram/SourceFiles/calls/group/calls_group_call.h @@ -244,7 +244,7 @@ public: void setCurrentAudioDevice(bool input, const QString &deviceId); void setCurrentVideoDevice(const QString &deviceId); bool isScreenSharing() const; - void switchToCamera(); + void toggleVideo(bool active); void switchToScreenSharing(const QString &uniqueId); void toggleMute(const Group::MuteRequest &data); diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp index cb0e2de1d..09821cce8 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.cpp @@ -685,30 +685,47 @@ void Panel::refreshLeftButton() { const auto share = _call->scheduleDate() && _peer->isBroadcast() && _peer->asChannel()->hasUsername(); - if ((share && _share) || (!share && _settings)) { + if ((share && _callShare) || (!share && _settings)) { return; } if (share) { _settings.destroy(); - _share.create(widget(), st::groupCallShare); - _share->setClickedCallback(_shareLinkCallback); - _share->setText(tr::lng_group_call_share_button()); + _callShare.create(widget(), st::groupCallShare); + _callShare->setClickedCallback(_callShareLinkCallback); + _callShare->setText(tr::lng_group_call_share_button()); } else { - _share.destroy(); + _callShare.destroy(); _settings.create(widget(), st::groupCallSettings); _settings->setClickedCallback([=] { - if (_call->isScreenSharing()) { - _call->switchToCamera(); - } else { - Ui::DesktopCapture::ChooseSource(this); - } - //_layerBg->showBox(Box(SettingsBox, _call)); + _layerBg->showBox(Box(SettingsBox, _call)); }); _settings->setText(tr::lng_group_call_settings()); } - const auto raw = _share ? _share.data() : _settings.data(); + const auto raw = _callShare ? _callShare.data() : _settings.data(); raw->show(); raw->setColorOverrides(_mute->colorOverrides()); + + if (!_video) { + _video.create(widget(), st::groupCallVideoSmall); + _video->show(); + _video->setClickedCallback([=] { + const auto sharing = _call->isScreenSharing(); + const auto active = (_call->outgoingVideoTrack()->state() + == Webrtc::VideoState::Active); + _call->toggleVideo(sharing || !active); + }); + _video->setText(tr::lng_group_call_video()); + _video->setColorOverrides(_mute->colorOverrides()); + } + if (!_screenShare) { + _screenShare.create(widget(), st::groupCallScreenShareSmall); + _screenShare->show(); + _screenShare->setClickedCallback([=] { + Ui::DesktopCapture::ChooseSource(this); + }); + _screenShare->setText(tr::lng_group_call_screen_share()); + _screenShare->setColorOverrides(_mute->colorOverrides()); + } } void Panel::initShareAction() { @@ -725,7 +742,7 @@ void Panel::initShareAction() { _peer, showBox, showToast); - _shareLinkCallback = [=, callback = std::move(shareLinkCallback)] { + _callShareLinkCallback = [=, callback = std::move(shareLinkCallback)] { if (_call->lookupReal()) { callback(); } @@ -911,7 +928,7 @@ void Panel::setupMembers() { _members->addMembersRequests( ) | rpl::start_with_next([=] { if (_peer->isBroadcast() && _peer->asChannel()->hasUsername()) { - _shareLinkCallback(); + _callShareLinkCallback(); } else { addMembers(); } @@ -1505,31 +1522,44 @@ bool Panel::updateMode() { } void Panel::updateControlsGeometry() { - if (widget()->size().isEmpty() || (!_settings && !_share)) { + if (widget()->size().isEmpty() || (!_settings && !_callShare)) { return; } if (_videoMode.current()) { _mute->setStyle(st::callMuteButtonSmall); const auto buttonsTop = widget()->height() - - st::groupCallButtonBottomSkip; - const auto muteSize = _mute->innerSize().width(); - const auto fullWidth = muteSize - + 2 * (_settings ? _settings : _share)->width() - + 2 * st::groupCallButtonSkip; - const auto leftButtonLeft = (widget()->width() - fullWidth) / 2; + - st::groupCallButtonBottomSkipSmall; const auto addSkip = st::callMuteButtonSmall.active.outerRadius; - _mute->moveInner({ leftButtonLeft + addSkip, buttonsTop + addSkip }); + const auto muteSize = _mute->innerSize().width() + 2 * addSkip; + const auto skip = (_video ? 1 : 2) * st::groupCallButtonSkipSmall; + const auto fullWidth = muteSize + + (_video ? _video->width() + skip : 0) + + (_screenShare ? _screenShare->width() + skip : 0) + + (_settings ? _settings : _callShare)->width() + skip + + _hangup->width() + skip; + auto left = (widget()->width() - fullWidth) / 2; + _mute->moveInner({ left + addSkip, buttonsTop + addSkip }); + left += muteSize + skip; + if (_video) { + _video->moveToLeft(left, buttonsTop); + left += _video->width() + skip; + } + if (_screenShare) { + _screenShare->moveToLeft(left, buttonsTop); + left += _video->width() + skip; + } if (_settings) { - _settings->moveToLeft( - (widget()->width() - _settings->width()) / 2, - buttonsTop); + _settings->setStyle(st::groupCallSettingsSmall); + _settings->moveToLeft(left, buttonsTop); + left += _settings->width() + skip; } - if (_share) { - _share->moveToLeft( - (widget()->width() - _share->width()) / 2, - buttonsTop); + if (_callShare) { + _callShare->setStyle(st::groupCallShareSmall); + _callShare->moveToLeft(left, buttonsTop); + left += _callShare->width() + skip; } - _hangup->moveToRight(leftButtonLeft, buttonsTop); + _hangup->setStyle(st::groupCallHangupSmall); + _hangup->moveToLeft(left, buttonsTop); } else { _mute->setStyle(st::callMuteButton); const auto muteTop = widget()->height() @@ -1538,16 +1568,19 @@ void Panel::updateControlsGeometry() { - st::groupCallButtonBottomSkip; const auto muteSize = _mute->innerSize().width(); const auto fullWidth = muteSize - + 2 * (_settings ? _settings : _share)->width() + + 2 * (_settings ? _settings : _callShare)->width() + 2 * st::groupCallButtonSkip; _mute->moveInner({ (widget()->width() - muteSize) / 2, muteTop }); const auto leftButtonLeft = (widget()->width() - fullWidth) / 2; if (_settings) { + _settings->setStyle(st::groupCallSettings); _settings->moveToLeft(leftButtonLeft, buttonsTop); } - if (_share) { - _share->moveToLeft(leftButtonLeft, buttonsTop); + if (_callShare) { + _callShare->setStyle(st::groupCallShare); + _callShare->moveToLeft(leftButtonLeft, buttonsTop); } + _hangup->setStyle(st::groupCallHangup); _hangup->moveToRight(leftButtonLeft, buttonsTop); } updateMembersGeometry(); diff --git a/Telegram/SourceFiles/calls/group/calls_group_panel.h b/Telegram/SourceFiles/calls/group/calls_group_panel.h index a963fbf62..c9b535424 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_panel.h +++ b/Telegram/SourceFiles/calls/group/calls_group_panel.h @@ -147,12 +147,12 @@ private: rpl::variable _videoMode; object_ptr _settings = { nullptr }; - object_ptr _share = { nullptr }; + object_ptr _callShare = { nullptr }; object_ptr _video = { nullptr }; - object_ptr _shareScreen = { nullptr }; + object_ptr _screenShare = { nullptr }; std::unique_ptr _mute; object_ptr _hangup; - Fn _shareLinkCallback; + Fn _callShareLinkCallback; rpl::lifetime _peerLifetime; diff --git a/Telegram/SourceFiles/ui/controls/call_mute_button.cpp b/Telegram/SourceFiles/ui/controls/call_mute_button.cpp index 8a5b6ad0a..76b1d6b95 100644 --- a/Telegram/SourceFiles/ui/controls/call_mute_button.cpp +++ b/Telegram/SourceFiles/ui/controls/call_mute_button.cpp @@ -175,11 +175,9 @@ public: int additionalHeight, const style::FlatLabel &st = st::defaultFlatLabel); - int height() const; + int contentHeight() const; private: - int realHeight() const; - void setText(const QString &text); const style::FlatLabel &_st; @@ -220,9 +218,9 @@ AnimatedLabel::AnimatedLabel( p.setPen(_st.textFg); p.setTextPalette(_st.palette); - const auto textHeight = height(); - const auto diffHeight = realHeight() - textHeight; - const auto center = (diffHeight) / 2; + const auto textHeight = contentHeight(); + const auto diffHeight = height() - textHeight; + const auto center = diffHeight / 2; p.setOpacity(1. - progress); if (p.opacity()) { @@ -246,14 +244,10 @@ AnimatedLabel::AnimatedLabel( }, lifetime()); } -int AnimatedLabel::height() const { +int AnimatedLabel::contentHeight() const { return _st.style.font->height; } -int AnimatedLabel::realHeight() const { - return RpWidget::height(); -} - void AnimatedLabel::setText(const QString &text) { if (_text.toString() == text) { return; @@ -264,7 +258,9 @@ void AnimatedLabel::setText(const QString &text) { const auto width = std::max( _st.style.font->width(_text.toString()), _st.style.font->width(_previousText.toString())); - resize(width + _additionalHeight, height() + _additionalHeight * 2); + resize( + width + _additionalHeight, + contentHeight() + _additionalHeight * 2); _animation.stop(); _animation.start([=] { update(); }, 0., 1., _duration); @@ -933,25 +929,31 @@ void CallMuteButton::updateLabelsGeometry() { void CallMuteButton::updateLabelGeometry(QRect my, QSize size) { const auto skip = _st->sublabelSkip + _st->labelsSkip; + const auto contentHeight = _label->contentHeight(); + const auto contentTop = my.y() + my.height() - contentHeight - skip; _label->moveToLeft( my.x() + (my.width() - size.width()) / 2 + _labelShakeShift, - my.y() + my.height() - size.height() - skip, + contentTop - (size.height() - contentHeight) / 2, my.width()); } void CallMuteButton::updateCenterLabelGeometry(QRect my, QSize size) { const auto skip = (_st->sublabelSkip / 2) + _st->labelsSkip; + const auto contentHeight = _centerLabel->contentHeight(); + const auto contentTop = my.y() + my.height() - contentHeight - skip; _centerLabel->moveToLeft( my.x() + (my.width() - size.width()) / 2 + _labelShakeShift, - my.y() + my.height() - size.height() - skip, + contentTop - (size.height() - contentHeight) / 2, my.width()); } void CallMuteButton::updateSublabelGeometry(QRect my, QSize size) { const auto skip = _st->labelsSkip; + const auto contentHeight = _sublabel->contentHeight(); + const auto contentTop = my.y() + my.height() - contentHeight - skip; _sublabel->moveToLeft( my.x() + (my.width() - size.width()) / 2 + _labelShakeShift, - my.y() + my.height() - size.height() - skip, + contentTop - (size.height() - contentHeight) / 2, my.width()); } diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 14c67cf72..3c1866f52 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 14c67cf724a572186455a8c0639f037ae26cc762 +Subproject commit 3c1866f52d88f9430341f9a9f1ed3dbbb3b794ea