Hide call controls in one-on-one video.

This commit is contained in:
John Preston 2025-02-11 11:46:42 +04:00
parent b885779365
commit dd2378b591
3 changed files with 145 additions and 11 deletions

View file

@ -578,8 +578,7 @@ void Instance::handleCallUpdate(
if (inCall()
&& _currentCall->type() == Call::Type::Outgoing
&& _currentCall->user()->id == session->userPeerId()
&& (peerFromUser(phoneCall.vparticipant_id())
== _currentCall->user()->session().userPeerId())) {
&& (user->id == _currentCall->user()->session().userPeerId())) {
// Ignore call from the same running app, other account.
return;
}

View file

@ -42,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/emoji_config.h"
#include "ui/painter.h"
#include "ui/rect.h"
#include "ui/integration.h"
#include "core/application.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
@ -65,6 +66,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Calls {
namespace {
constexpr auto kHideControlsTimeout = 5 * crl::time(1000);
constexpr auto kHideControlsQuickTimeout = 2 * crl::time(1000);
[[nodiscard]] QByteArray BatterySvg(
const QSize &s,
const QColor &c) {
@ -118,7 +122,9 @@ Panel::Panel(not_null<Call*> call)
st::callMicrophoneMute,
&st::callMicrophoneUnmute))
, _name(widget(), st::callName)
, _status(widget(), st::callStatus) {
, _status(widget(), st::callStatus)
, _hideControlsTimer([=] { requestControlsHidden(true); })
, _controlsShownForceTimer([=] { controlsShownForce(false); }) {
_layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox);
_layerBg->setHideByBackgroundClick(true);
@ -188,6 +194,25 @@ void Panel::initWindow() {
&& window()->isFullScreen()) {
window()->showNormal();
}
} else if (e->type() == QEvent::WindowStateChange) {
const auto state = window()->windowState();
_fullScreenOrMaximized = (state & Qt::WindowFullScreen)
|| (state & Qt::WindowMaximized);
} else if (e->type() == QEvent::Enter) {
_mouseInside = true;
Ui::Integration::Instance().registerLeaveSubscription(
window().get());
if (!_fullScreenOrMaximized.current()) {
requestControlsHidden(false);
_hideControlsTimer.cancel();
}
} else if (e->type() == QEvent::Leave) {
_mouseInside = false;
Ui::Integration::Instance().unregisterLeaveSubscription(
window().get());
if (!_fullScreenOrMaximized.current()) {
_hideControlsTimer.callOnce(kHideControlsQuickTimeout);
}
}
return base::EventFilterResult::Continue;
});
@ -415,7 +440,11 @@ void Panel::refreshIncomingGeometry() {
void Panel::reinitWithCall(Call *call) {
_callLifetime.destroy();
_call = call;
const auto guard = gsl::finally([&] {
updateControlsShown();
});
if (!_call) {
_fingerprint.destroy();
_incoming = nullptr;
_outgoingVideoBubble = nullptr;
_powerSaveBlocker = nullptr;
@ -457,6 +486,51 @@ void Panel::reinitWithCall(Call *call) {
_window.backend());
_incoming->widget()->hide();
_incoming->rp()->shownValue() | rpl::start_with_next([=] {
updateControlsShown();
}, _incoming->rp()->lifetime());
_hideControlsFilter = nullptr;
_fullScreenOrMaximized.value(
) | rpl::start_with_next([=](bool fullScreenOrMaximized) {
if (fullScreenOrMaximized) {
class Filter final : public QObject {
public:
explicit Filter(Fn<void(QObject*)> moved) : _moved(moved) {
qApp->installEventFilter(this);
}
bool eventFilter(QObject *watched, QEvent *event) {
if (event->type() == QEvent::MouseMove) {
_moved(watched);
}
return false;
}
private:
Fn<void(QObject*)> _moved;
};
_hideControlsFilter.reset(new Filter([=](QObject *what) {
_mouseInside = true;
if (what->isWidgetType()
&& window()->isAncestorOf(static_cast<QWidget*>(what))) {
_hideControlsTimer.callOnce(kHideControlsTimeout);
requestControlsHidden(false);
updateControlsShown();
}
}));
_hideControlsTimer.callOnce(kHideControlsTimeout);
} else {
_hideControlsFilter = nullptr;
_hideControlsTimer.cancel();
if (_mouseInside) {
requestControlsHidden(false);
updateControlsShown();
}
}
}, _incoming->rp()->lifetime());
_call->mutedValue(
) | rpl::start_with_next([=](bool mute) {
_mute->entity()->setProgress(mute ? 1. : 0.);
@ -603,6 +677,8 @@ void Panel::createRemoteAudioMute() {
const auto r = _remoteAudioMute->rect();
auto hq = PainterHighQualityEnabler(p);
p.setOpacity(_controlsShownAnimation.value(
_controlsShown ? 1. : 0.));
p.setBrush(st::videoPlayIconBg);
p.setPen(Qt::NoPen);
p.drawRoundedRect(r, r.height() / 2, r.height() / 2);
@ -661,6 +737,8 @@ void Panel::createRemoteLowBattery() {
const auto r = _remoteLowBattery->rect();
auto hq = PainterHighQualityEnabler(p);
p.setOpacity(_controlsShownAnimation.value(
_controlsShown ? 1. : 0.));
p.setBrush(st::videoPlayIconBg);
p.setPen(Qt::NoPen);
p.drawRoundedRect(r, r.height() / 2, r.height() / 2);
@ -782,6 +860,9 @@ void Panel::showDevicesMenu(
}
Core::App().saveSettingsDelayed();
};
controlsShownForce(true);
updateControlsShown();
_devicesMenu = MakeDeviceSelectionMenu(
widget(),
&Core::App().mediaDevices(),
@ -791,6 +872,9 @@ void Panel::showDevicesMenu(
Ui::PopupMenu::VerticalOrigin::Bottom);
_devicesMenu->popup(button->mapToGlobal(QPoint())
- QPoint(st::callDeviceSelectionMenu.menu.widthMin / 2, 0));
QObject::connect(_devicesMenu.get(), &QObject::destroyed, window(), [=] {
_controlsShownForceTimer.callOnce(kHideControlsQuickTimeout);
});
}
void Panel::refreshOutgoingPreviewInBody(State state) {
@ -823,6 +907,33 @@ QRect Panel::outgoingFrameGeometry() const {
return _outgoingVideoBubble->geometry();
}
void Panel::requestControlsHidden(bool hidden) {
_hideControlsRequested = hidden;
updateControlsShown();
}
void Panel::controlsShownForce(bool shown) {
_controlsShownForce = shown;
if (shown) {
_controlsShownForceTimer.cancel();
}
updateControlsShown();
}
void Panel::updateControlsShown() {
const auto shown = !_incoming
|| _incoming->widget()->isHidden()
|| _controlsShownForce
|| !_hideControlsRequested;
if (_controlsShown != shown) {
_controlsShown = shown;
_controlsShownAnimation.start([=] {
updateControlsGeometry();
}, shown ? 0. : 1., shown ? 1. : 0., st::slideDuration);
updateControlsGeometry();
}
}
void Panel::updateControlsGeometry() {
if (widget()->size().isEmpty()) {
return;
@ -830,6 +941,8 @@ void Panel::updateControlsGeometry() {
if (_incoming) {
refreshIncomingGeometry();
}
const auto shown = _controlsShownAnimation.value(
_controlsShown ? 1. : 0.);
if (_fingerprint) {
#ifndef Q_OS_MAC
const auto controlsGeometry = _controls->controls.geometry();
@ -848,14 +961,14 @@ void Panel::updateControlsGeometry() {
const auto minRight = 0;
#endif // _controls
const auto desired = (widget()->width() - _fingerprint->width()) / 2;
const auto top = anim::interpolate(
-_fingerprint->height(),
st::callFingerprintTop,
shown);
if (minLeft) {
_fingerprint->moveToLeft(
std::max(desired, minLeft),
st::callFingerprintTop);
_fingerprint->moveToLeft(std::max(desired, minLeft), top);
} else {
_fingerprint->moveToRight(
std::max(desired, minRight),
st::callFingerprintTop);
_fingerprint->moveToRight(std::max(desired, minRight), top);
}
}
const auto innerHeight = std::max(widget()->height(), st::callHeightMin);
@ -885,7 +998,11 @@ void Panel::updateControlsGeometry() {
/ (_outgoingPreviewInBody ? 3 : 2);
_bodyTop = availableTop + skipHeight;
_buttonsTop = availableTop + available;
_buttonsTopShown = availableTop + available;
_buttonsTop = anim::interpolate(
widget()->height(),
_buttonsTopShown,
shown);
const auto previewTop = _bodyTop + _bodySt->height + skipHeight;
_userpic->setGeometry(
@ -908,6 +1025,8 @@ void Panel::updateControlsGeometry() {
(_buttonsTop
- st::callRemoteAudioMuteSkip
- _remoteAudioMute->height()));
_remoteAudioMute->update();
_remoteAudioMute->entity()->setOpacity(shown);
}
if (_remoteLowBattery) {
_remoteLowBattery->moveToLeft(
@ -915,6 +1034,8 @@ void Panel::updateControlsGeometry() {
(_buttonsTop
- st::callRemoteAudioMuteSkip
- _remoteLowBattery->height()));
_remoteLowBattery->update();
_remoteLowBattery->entity()->setOpacity(shown);
}
if (_outgoingPreviewInBody) {
@ -925,7 +1046,7 @@ void Panel::updateControlsGeometry() {
previewTop,
bodyPreviewSize.width(),
bodyPreviewSize.height()));
} else {
} else if (_outgoingVideoBubble) {
updateOutgoingVideoBubbleGeometry();
}

View file

@ -111,6 +111,9 @@ private:
[[nodiscard]] bool handleClose() const;
void requestControlsHidden(bool hidden);
void controlsShownForce(bool shown);
void updateControlsShown();
void updateControlsGeometry();
void updateHangupGeometry();
void updateStatusGeometry();
@ -177,8 +180,19 @@ private:
std::unique_ptr<VideoBubble> _outgoingVideoBubble;
QPixmap _bottomShadow;
int _bodyTop = 0;
int _buttonsTopShown = 0;
int _buttonsTop = 0;
base::Timer _hideControlsTimer;
base::Timer _controlsShownForceTimer;
std::unique_ptr<QObject> _hideControlsFilter;
bool _hideControlsRequested = false;
rpl::variable<bool> _fullScreenOrMaximized;
Ui::Animations::Simple _controlsShownAnimation;
bool _controlsShownForce = false;
bool _controlsShown = true;
bool _mouseInside = false;
base::unique_qptr<Ui::PopupMenu> _devicesMenu;
base::Timer _updateDurationTimer;