Reuse p2p call window for migrated confcall.

This commit is contained in:
John Preston 2025-04-08 17:24:31 +04:00
parent 915dec7ba5
commit 59e56600bc
17 changed files with 606 additions and 545 deletions

View file

@ -396,6 +396,8 @@ PRIVATE
calls/calls_video_bubble.h calls/calls_video_bubble.h
calls/calls_video_incoming.cpp calls/calls_video_incoming.cpp
calls/calls_video_incoming.h calls/calls_video_incoming.h
calls/calls_window.cpp
calls/calls_window.h
chat_helpers/compose/compose_features.h chat_helpers/compose/compose_features.h
chat_helpers/compose/compose_show.cpp chat_helpers/compose/compose_show.cpp
chat_helpers/compose/compose_show.h chat_helpers/compose/compose_show.h

View file

@ -4955,7 +4955,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_confcall_invite_fail_user" = "Couldn't call {user} to join."; "lng_confcall_invite_fail_user" = "Couldn't call {user} to join.";
"lng_confcall_invite_fail_many#one" = "Couldn't call **{count} person** to join."; "lng_confcall_invite_fail_many#one" = "Couldn't call **{count} person** to join.";
"lng_confcall_invite_fail_many#other" = "Couldn't call **{count} people** to join."; "lng_confcall_invite_fail_many#other" = "Couldn't call **{count} people** to join.";
"lng_confcall_invite_kicked_user" = "{user} was removed from the call."; "lng_confcall_invite_kicked_user" = "{user} was banned from the call.";
"lng_confcall_invite_kicked_many#one" = "**{count} person** was removed from the call."; "lng_confcall_invite_kicked_many#one" = "**{count} person** was removed from the call.";
"lng_confcall_invite_kicked_many#other" = "**{count} people** were removed from the call."; "lng_confcall_invite_kicked_many#other" = "**{count} people** were removed from the call.";
"lng_confcall_not_accessible" = "This call is no longer accessible."; "lng_confcall_not_accessible" = "This call is no longer accessible.";

View file

@ -20,7 +20,7 @@ namespace GroupCalls {
class ListController : public PeerListController { class ListController : public PeerListController {
public: public:
explicit ListController(not_null<Window::SessionController*> window); explicit ListController(not_null<::Window::SessionController*> window);
[[nodiscard]] rpl::producer<bool> shownValue() const; [[nodiscard]] rpl::producer<bool> shownValue() const;
@ -30,7 +30,7 @@ public:
void rowRightActionClicked(not_null<PeerListRow*> row) override; void rowRightActionClicked(not_null<PeerListRow*> row) override;
private: private:
const not_null<Window::SessionController*> _window; const not_null<::Window::SessionController*> _window;
base::flat_map<PeerId, not_null<PeerListRow*>> _groupCalls; base::flat_map<PeerId, not_null<PeerListRow*>> _groupCalls;
rpl::variable<int> _fullCount; rpl::variable<int> _fullCount;
@ -40,7 +40,7 @@ private:
class BoxController : public PeerListController { class BoxController : public PeerListController {
public: public:
explicit BoxController(not_null<Window::SessionController*> window); explicit BoxController(not_null<::Window::SessionController*> window);
Main::Session &session() const override; Main::Session &session() const override;
void prepare() override; void prepare() override;
@ -68,7 +68,7 @@ private:
std::unique_ptr<PeerListRow> createRow( std::unique_ptr<PeerListRow> createRow(
not_null<HistoryItem*> item) const; not_null<HistoryItem*> item) const;
const not_null<Window::SessionController*> _window; const not_null<::Window::SessionController*> _window;
MTP::Sender _api; MTP::Sender _api;
MsgId _offsetId = 0; MsgId _offsetId = 0;
@ -79,6 +79,6 @@ private:
void ClearCallsBox( void ClearCallsBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<Window::SessionController*> window); not_null<::Window::SessionController*> window);
} // namespace Calls } // namespace Calls

View file

@ -811,7 +811,7 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
} }
if (data.is_need_rating() && _id && _accessHash) { if (data.is_need_rating() && _id && _accessHash) {
const auto window = Core::App().windowFor( const auto window = Core::App().windowFor(
Window::SeparateId(_user)); ::Window::SeparateId(_user));
const auto session = &_user->session(); const auto session = &_user->session();
const auto callId = _id; const auto callId = _id;
const auto callAccessHash = _accessHash; const auto callAccessHash = _accessHash;
@ -1589,7 +1589,7 @@ void Call::handleRequestError(const QString &error) {
: error; : error;
if (!inform.isEmpty()) { if (!inform.isEmpty()) {
if (const auto window = Core::App().windowFor( if (const auto window = Core::App().windowFor(
Window::SeparateId(_user))) { ::Window::SeparateId(_user))) {
window->show(Ui::MakeInformBox(inform)); window->show(Ui::MakeInformBox(inform));
} else { } else {
Ui::show(Ui::MakeInformBox(inform)); Ui::show(Ui::MakeInformBox(inform));
@ -1608,7 +1608,7 @@ void Call::handleControllerError(const QString &error) {
: QString(); : QString();
if (!inform.isEmpty()) { if (!inform.isEmpty()) {
if (const auto window = Core::App().windowFor( if (const auto window = Core::App().windowFor(
Window::SeparateId(_user))) { ::Window::SeparateId(_user))) {
window->show(Ui::MakeInformBox(inform)); window->show(Ui::MakeInformBox(inform));
} else { } else {
Ui::show(Ui::MakeInformBox(inform)); Ui::show(Ui::MakeInformBox(inform));

View file

@ -153,7 +153,7 @@ std::vector<EmojiPtr> ComputeEmojiFingerprint(
return result; return result;
} }
object_ptr<Ui::RpWidget> CreateFingerprintAndSignalBars( base::unique_qptr<Ui::RpWidget> CreateFingerprintAndSignalBars(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Call*> call) { not_null<Call*> call) {
class EmojiTooltipShower final : public Ui::AbstractTooltipShower { class EmojiTooltipShower final : public Ui::AbstractTooltipShower {
@ -179,8 +179,8 @@ object_ptr<Ui::RpWidget> CreateFingerprintAndSignalBars(
}; };
auto result = object_ptr<Ui::RpWidget>(parent); auto result = base::make_unique_q<Ui::RpWidget>(parent);
const auto raw = result.data(); const auto raw = result.get();
// Emoji tooltip. // Emoji tooltip.
const auto shower = raw->lifetime().make_state<EmojiTooltipShower>( const auto shower = raw->lifetime().make_state<EmojiTooltipShower>(

View file

@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/object_ptr.h" #include "base/unique_qptr.h"
namespace Ui { namespace Ui {
class RpWidget; class RpWidget;
@ -22,7 +22,7 @@ class Call;
[[nodiscard]] std::vector<EmojiPtr> ComputeEmojiFingerprint( [[nodiscard]] std::vector<EmojiPtr> ComputeEmojiFingerprint(
bytes::const_span fingerprint); bytes::const_span fingerprint);
[[nodiscard]] object_ptr<Ui::RpWidget> CreateFingerprintAndSignalBars( [[nodiscard]] base::unique_qptr<Ui::RpWidget> CreateFingerprintAndSignalBars(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<Call*> call); not_null<Call*> call);

View file

@ -349,7 +349,11 @@ void Instance::playSoundOnce(const QString &key) {
void Instance::destroyCall(not_null<Call*> call) { void Instance::destroyCall(not_null<Call*> call) {
if (_currentCall.get() == call) { if (_currentCall.get() == call) {
_currentCallPanel->closeBeforeDestroy(); const auto groupCallWindow = _currentGroupCallPanel
? _currentGroupCallPanel->window().get()
: nullptr;
const auto reused = (_currentCallPanel->window() == groupCallWindow);
_currentCallPanel->closeBeforeDestroy(reused);
_currentCallPanel = nullptr; _currentCallPanel = nullptr;
auto taken = base::take(_currentCall); auto taken = base::take(_currentCall);

View file

@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/calls_userpic.h" #include "calls/calls_userpic.h"
#include "calls/calls_video_bubble.h" #include "calls/calls_video_bubble.h"
#include "calls/calls_video_incoming.h" #include "calls/calls_video_incoming.h"
#include "calls/calls_window.h"
#include "ui/platform/ui_platform_window_title.h" #include "ui/platform/ui_platform_window_title.h"
#include "ui/widgets/call_button.h" #include "ui/widgets/call_button.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
@ -95,116 +96,49 @@ constexpr auto kHideControlsQuickTimeout = 2 * crl::time(1000);
</svg>)"; </svg>)";
} }
class Show final : public Main::SessionShow {
public:
explicit Show(not_null<Panel*> panel);
~Show();
void showOrHideBoxOrLayer(
std::variant<
v::null_t,
object_ptr<Ui::BoxContent>,
std::unique_ptr<Ui::LayerWidget>> &&layer,
Ui::LayerOptions options,
anim::type animated) const override;
[[nodiscard]] not_null<QWidget*> toastParent() const override;
[[nodiscard]] bool valid() const override;
operator bool() const override;
[[nodiscard]] Main::Session &session() const override;
private:
const base::weak_ptr<Panel> _panel;
};
Show::Show(not_null<Panel*> panel)
: _panel(base::make_weak(panel)) {
}
Show::~Show() = default;
void Show::showOrHideBoxOrLayer(
std::variant<
v::null_t,
object_ptr<Ui::BoxContent>,
std::unique_ptr<Ui::LayerWidget>> &&layer,
Ui::LayerOptions options,
anim::type animated) const {
using UniqueLayer = std::unique_ptr<Ui::LayerWidget>;
using ObjectBox = object_ptr<Ui::BoxContent>;
if (auto layerWidget = std::get_if<UniqueLayer>(&layer)) {
if (const auto panel = _panel.get()) {
panel->showLayer(std::move(*layerWidget), options, animated);
}
} else if (auto box = std::get_if<ObjectBox>(&layer)) {
if (const auto panel = _panel.get()) {
panel->showBox(std::move(*box), options, animated);
}
} else if (const auto panel = _panel.get()) {
panel->hideLayer(animated);
}
}
not_null<QWidget*> Show::toastParent() const {
const auto panel = _panel.get();
Assert(panel != nullptr);
return panel->widget();
}
bool Show::valid() const {
return !_panel.empty();
}
Show::operator bool() const {
return valid();
}
Main::Session &Show::session() const {
const auto panel = _panel.get();
Assert(panel != nullptr);
return panel->user()->session();
}
} // namespace } // namespace
Panel::Panel(not_null<Call*> call) Panel::Panel(not_null<Call*> call)
: _call(call) : _call(call)
, _user(call->user()) , _user(call->user())
, _layerBg(std::make_unique<Ui::LayerManager>(widget())) , _window(std::make_shared<Window>())
#ifndef Q_OS_MAC
, _controls(Ui::Platform::SetupSeparateTitleControls(
window(),
st::callTitle,
[=](bool maximized) { toggleFullScreen(maximized); }))
#endif // !Q_OS_MAC
, _bodySt(&st::callBodyLayout) , _bodySt(&st::callBodyLayout)
, _answerHangupRedial(widget(), st::callAnswer, &st::callHangup) , _answerHangupRedial(
, _decline(widget(), object_ptr<Ui::CallButton>(widget(), st::callHangup)) std::in_place,
, _cancel(widget(), object_ptr<Ui::CallButton>(widget(), st::callCancel)) widget(),
st::callAnswer,
&st::callHangup)
, _decline(
std::in_place,
widget(),
object_ptr<Ui::CallButton>(widget(), st::callHangup))
, _cancel(
std::in_place,
widget(),
object_ptr<Ui::CallButton>(widget(), st::callCancel))
, _screencast( , _screencast(
std::in_place,
widget(), widget(),
object_ptr<Ui::CallButton>( object_ptr<Ui::CallButton>(
widget(), widget(),
st::callScreencastOn, st::callScreencastOn,
&st::callScreencastOff)) &st::callScreencastOff))
, _camera(widget(), st::callCameraMute, &st::callCameraUnmute) , _camera(std::in_place, widget(), st::callCameraMute, &st::callCameraUnmute)
, _mute( , _mute(
std::in_place,
widget(), widget(),
object_ptr<Ui::CallButton>( object_ptr<Ui::CallButton>(
widget(), widget(),
st::callMicrophoneMute, st::callMicrophoneMute,
&st::callMicrophoneUnmute)) &st::callMicrophoneUnmute))
, _addPeople( , _addPeople(
std::in_place,
widget(), widget(),
object_ptr<Ui::CallButton>(widget(), st::callAddPeople)) object_ptr<Ui::CallButton>(widget(), st::callAddPeople))
, _name(widget(), st::callName) , _name(std::in_place, widget(), st::callName)
, _status(widget(), st::callStatus) , _status(std::in_place, widget(), st::callStatus)
, _hideControlsTimer([=] { requestControlsHidden(true); }) , _hideControlsTimer([=] { requestControlsHidden(true); })
, _controlsShownForceTimer([=] { controlsShownForce(false); }) { , _controlsShownForceTimer([=] { controlsShownForce(false); }) {
_layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox);
_layerBg->setHideByBackgroundClick(true);
_decline->setDuration(st::callPanelDuration); _decline->setDuration(st::callPanelDuration);
_decline->entity()->setText(tr::lng_call_decline()); _decline->entity()->setText(tr::lng_call_decline());
_cancel->setDuration(st::callPanelDuration); _cancel->setDuration(st::callPanelDuration);
@ -234,67 +168,15 @@ bool Panel::isActive() const {
} }
ConferencePanelMigration Panel::migrationInfo() const { ConferencePanelMigration Panel::migrationInfo() const {
const auto handle = window()->windowHandle(); return ConferencePanelMigration{ .window = _window };
return handle ? ConferencePanelMigration{
.screen = handle->screen(),
.geometry = window()->geometry(),
} : ConferencePanelMigration();
} }
base::weak_ptr<Ui::Toast::Instance> Panel::showToast( std::shared_ptr<Main::SessionShow> Panel::sessionShow() {
const QString &text, return Main::MakeSessionShow(uiShow(), &_user->session());
crl::time duration) {
return showToast({
.text = { text },
.duration = duration,
});
} }
base::weak_ptr<Ui::Toast::Instance> Panel::showToast( std::shared_ptr<Ui::Show> Panel::uiShow() {
TextWithEntities &&text, return _window->uiShow();
crl::time duration) {
return showToast({
.text = std::move(text),
.duration = duration,
});
}
base::weak_ptr<Ui::Toast::Instance> Panel::showToast(
Ui::Toast::Config &&config) {
if (!config.st) {
config.st = &st::callErrorToast;
}
return Show(this).showToast(std::move(config));
}
void Panel::showBox(object_ptr<Ui::BoxContent> box) {
showBox(std::move(box), Ui::LayerOption::KeepOther, anim::type::normal);
}
void Panel::showBox(
object_ptr<Ui::BoxContent> box,
Ui::LayerOptions options,
anim::type animated) {
_layerBg->showBox(std::move(box), options, animated);
}
void Panel::showLayer(
std::unique_ptr<Ui::LayerWidget> layer,
Ui::LayerOptions options,
anim::type animated) {
_layerBg->showLayer(std::move(layer), options, animated);
}
void Panel::hideLayer(anim::type animated) {
_layerBg->hideAll(animated);
}
bool Panel::isLayerShown() const {
return _layerBg->topShownLayer() != nullptr;
}
std::shared_ptr<Main::SessionShow> Panel::uiShow() {
return std::make_shared<Show>(this);
} }
void Panel::showAndActivate() { void Panel::showAndActivate() {
@ -359,20 +241,16 @@ void Panel::initWindow() {
} }
} }
return base::EventFilterResult::Continue; return base::EventFilterResult::Continue;
}); }, lifetime());
const auto guard = base::make_weak(this);
window()->setBodyTitleArea([=](QPoint widgetPoint) { window()->setBodyTitleArea([=](QPoint widgetPoint) {
using Flag = Ui::WindowTitleHitTestFlag; using Flag = Ui::WindowTitleHitTestFlag;
if (!widget()->rect().contains(widgetPoint)) { if (!guard
|| !widget()->rect().contains(widgetPoint)
|| _window->controlsHasHitTest(widgetPoint)) {
return Flag::None | Flag(0); return Flag::None | Flag(0);
} }
#ifndef Q_OS_MAC
using Result = Ui::Platform::HitTestResult;
const auto windowPoint = widget()->mapTo(window(), widgetPoint);
if (_controls->controls.hitTest(windowPoint) != Result::None) {
return Flag::None | Flag(0);
}
#endif // !Q_OS_MAC
const auto buttonWidth = st::callCancel.button.width; const auto buttonWidth = st::callCancel.button.width;
const auto buttonsWidth = buttonWidth * 4; const auto buttonsWidth = buttonWidth * 4;
const auto inControls = (_fingerprint const auto inControls = (_fingerprint
@ -387,12 +265,15 @@ void Panel::initWindow() {
if (inControls) { if (inControls) {
return Flag::None | Flag(0); return Flag::None | Flag(0);
} }
const auto shown = _layerBg->topShownLayer(); const auto shown = _window->topShownLayer();
return (!shown || !shown->geometry().contains(widgetPoint)) return (!shown || !shown->geometry().contains(widgetPoint))
? (Flag::Move | Flag::Menu | Flag::FullScreen) ? (Flag::Move | Flag::Menu | Flag::FullScreen)
: Flag::None; : Flag::None;
}); });
_window->maximizeRequests() | rpl::start_with_next([=](bool maximized) {
toggleFullScreen(maximized);
}, lifetime());
// Don't do that, it looks awful :( // Don't do that, it looks awful :(
//#ifdef Q_OS_WIN //#ifdef Q_OS_WIN
// // On Windows we replace snap-to-top maximizing with fullscreen. // // On Windows we replace snap-to-top maximizing with fullscreen.
@ -426,12 +307,12 @@ void Panel::initWidget() {
widget()->paintRequest( widget()->paintRequest(
) | rpl::start_with_next([=](QRect clip) { ) | rpl::start_with_next([=](QRect clip) {
paint(clip); paint(clip);
}, widget()->lifetime()); }, lifetime());
widget()->sizeValue( widget()->sizeValue(
) | rpl::skip(1) | rpl::start_with_next([=] { ) | rpl::skip(1) | rpl::start_with_next([=] {
updateControlsGeometry(); updateControlsGeometry();
}, widget()->lifetime()); }, lifetime());
} }
void Panel::initControls() { void Panel::initControls() {
@ -447,7 +328,7 @@ void Panel::initControls() {
return; return;
} else if (!env->desktopCaptureAllowed()) { } else if (!env->desktopCaptureAllowed()) {
if (auto box = Group::ScreenSharingPrivacyRequestBox()) { if (auto box = Group::ScreenSharingPrivacyRequestBox()) {
showBox(std::move(box)); uiShow()->showBox(std::move(box));
} }
} else if (const auto source = env->uniqueDesktopCaptureSource()) { } else if (const auto source = env->uniqueDesktopCaptureSource()) {
if (!chooseSourceActiveDeviceId().isEmpty()) { if (!chooseSourceActiveDeviceId().isEmpty()) {
@ -467,7 +348,7 @@ void Panel::initControls() {
}); });
_addPeople->entity()->setClickedCallback([=] { _addPeople->entity()->setClickedCallback([=] {
if (!_call || _call->state() != Call::State::Established) { if (!_call || _call->state() != Call::State::Established) {
showToast(tr::lng_call_error_add_not_started(tr::now)); uiShow()->showToast(tr::lng_call_error_add_not_started(tr::now));
return; return;
} }
const auto call = _call; const auto call = _call;
@ -484,7 +365,7 @@ void Panel::initControls() {
*creating = true; *creating = true;
const auto sharingLink = users.empty(); const auto sharingLink = users.empty();
Group::MakeConferenceCall({ Group::MakeConferenceCall({
.show = uiShow(), .show = sessionShow(),
.finished = finish, .finished = finish,
.joining = true, .joining = true,
.info = { .info = {
@ -506,7 +387,7 @@ void Panel::initControls() {
const auto share = crl::guard(call, [=] { const auto share = crl::guard(call, [=] {
create({}); create({});
}); });
showBox(Group::PrepareInviteBox(call, invite, share)); uiShow()->showBox(Group::PrepareInviteBox(call, invite, share));
}); });
_updateDurationTimer.setCallback([this] { _updateDurationTimer.setCallback([this] {
@ -559,9 +440,9 @@ void Panel::initConferenceInvite() {
if (count < 2) { if (count < 2) {
return; return;
} }
_conferenceParticipants.create(widget()); _conferenceParticipants = base::make_unique_q<Ui::RpWidget>(widget());
_conferenceParticipants->show(); _conferenceParticipants->show();
const auto raw = _conferenceParticipants.data(); const auto raw = _conferenceParticipants.get();
auto peers = std::vector<not_null<PeerData*>>(); auto peers = std::vector<not_null<PeerData*>>();
for (const auto &peer : participants) { for (const auto &peer : participants) {
@ -689,10 +570,9 @@ void Panel::reinitWithCall(Call *call) {
updateControlsShown(); updateControlsShown();
}); });
if (!_call) { if (!_call) {
_fingerprint.destroy(); _fingerprint = nullptr;
_incoming = nullptr; _incoming = nullptr;
_outgoingVideoBubble = nullptr; _outgoingVideoBubble = nullptr;
_powerSaveBlocker = nullptr;
return; return;
} }
@ -716,7 +596,7 @@ void Panel::reinitWithCall(Call *call) {
if (muted) { if (muted) {
createRemoteAudioMute(); createRemoteAudioMute();
} else { } else {
_remoteAudioMute.destroy(); _remoteAudioMute = nullptr;
showRemoteLowBattery(); showRemoteLowBattery();
} }
}, _callLifetime); }, _callLifetime);
@ -725,7 +605,7 @@ void Panel::reinitWithCall(Call *call) {
if (state == Call::RemoteBatteryState::Low) { if (state == Call::RemoteBatteryState::Low) {
createRemoteLowBattery(); createRemoteLowBattery();
} else { } else {
_remoteLowBattery.destroy(); _remoteLowBattery = nullptr;
} }
}, _callLifetime); }, _callLifetime);
_userpic = std::make_unique<Userpic>( _userpic = std::make_unique<Userpic>(
@ -738,7 +618,7 @@ void Panel::reinitWithCall(Call *call) {
_incoming = std::make_unique<Incoming>( _incoming = std::make_unique<Incoming>(
widget(), widget(),
_call->videoIncoming(), _call->videoIncoming(),
_window.backend()); _window->backend());
_incoming->widget()->hide(); _incoming->widget()->hide();
_incoming->rp()->shownValue() | rpl::start_with_next([=] { _incoming->rp()->shownValue() | rpl::start_with_next([=] {
@ -886,7 +766,7 @@ void Panel::reinitWithCall(Call *call) {
} }
Unexpected("Error type in _call->errors()."); Unexpected("Error type in _call->errors().");
}(); }();
showToast(text); uiShow()->showToast(text);
}, _callLifetime); }, _callLifetime);
_name->setText(_user->name()); _name->setText(_user->name());
@ -902,16 +782,11 @@ void Panel::reinitWithCall(Call *call) {
_mute->raise(); _mute->raise();
_addPeople->raise(); _addPeople->raise();
_powerSaveBlocker = std::make_unique<base::PowerSaveBlocker>(
base::PowerSaveBlockType::PreventDisplaySleep,
u"Video call is active"_q,
window()->windowHandle());
_incoming->widget()->lower(); _incoming->widget()->lower();
} }
void Panel::createRemoteAudioMute() { void Panel::createRemoteAudioMute() {
_remoteAudioMute.create( _remoteAudioMute = base::make_unique_q<Ui::PaddingWrap<Ui::FlatLabel>>(
widget(), widget(),
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
widget(), widget(),
@ -948,7 +823,7 @@ void Panel::createRemoteAudioMute() {
} }
void Panel::createRemoteLowBattery() { void Panel::createRemoteLowBattery() {
_remoteLowBattery.create( _remoteLowBattery = base::make_unique_q<Ui::PaddingWrap<Ui::FlatLabel>>(
widget(), widget(),
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
widget(), widget(),
@ -964,7 +839,7 @@ void Panel::createRemoteLowBattery() {
style::PaletteChanged( style::PaletteChanged(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
_remoteLowBattery.destroy(); _remoteLowBattery = nullptr;
createRemoteLowBattery(); createRemoteLowBattery();
}, _remoteLowBattery->lifetime()); }, _remoteLowBattery->lifetime());
@ -1032,11 +907,9 @@ void Panel::initLayout() {
}) | rpl::start_with_next([=](const Data::PeerUpdate &update) { }) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
_name->setText(_call->user()->name()); _name->setText(_call->user()->name());
updateControlsGeometry(); updateControlsGeometry();
}, widget()->lifetime()); }, lifetime());
#ifndef Q_OS_MAC _window->raiseControls();
_controls->wrap.raise();
#endif // !Q_OS_MAC
} }
void Panel::showControls() { void Panel::showControls() {
@ -1058,13 +931,16 @@ void Panel::showControls() {
showRemoteLowBattery(); showRemoteLowBattery();
} }
void Panel::closeBeforeDestroy() { void Panel::closeBeforeDestroy(bool windowIsReused) {
window()->close(); if (!windowIsReused) {
window()->close();
}
reinitWithCall(nullptr); reinitWithCall(nullptr);
_lifetime.destroy();
} }
rpl::lifetime &Panel::lifetime() { rpl::lifetime &Panel::lifetime() {
return window()->lifetime(); return _lifetime;
} }
void Panel::initGeometry() { void Panel::initGeometry() {
@ -1202,7 +1078,7 @@ void Panel::updateControlsGeometry() {
_controlsShown ? 1. : 0.); _controlsShown ? 1. : 0.);
if (_fingerprint) { if (_fingerprint) {
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
const auto controlsGeometry = _controls->controls.geometry(); const auto controlsGeometry = _window->controlsGeometry();
const auto halfWidth = widget()->width() / 2; const auto halfWidth = widget()->width() / 2;
const auto minLeft = (controlsGeometry.center().x() < halfWidth) const auto minLeft = (controlsGeometry.center().x() < halfWidth)
? (controlsGeometry.width() + st::callFingerprintTop) ? (controlsGeometry.width() + st::callFingerprintTop)
@ -1391,11 +1267,11 @@ bool Panel::handleClose() const {
} }
not_null<Ui::RpWindow*> Panel::window() const { not_null<Ui::RpWindow*> Panel::window() const {
return _window.window(); return _window->window();
} }
not_null<Ui::RpWidget*> Panel::widget() const { not_null<Ui::RpWidget*> Panel::widget() const {
return _window.widget(); return _window->widget();
} }
not_null<UserData*> Panel::user() const { not_null<UserData*> Panel::user() const {
@ -1407,17 +1283,16 @@ void Panel::stateChanged(State state) {
updateStatusText(state); updateStatusText(state);
const auto isBusy = (state == State::Busy);
const auto isWaitingUser = (state == State::WaitingUserConfirmation);
_window->togglePowerSaveBlocker(!isBusy && !isWaitingUser);
if ((state != State::HangingUp) if ((state != State::HangingUp)
&& (state != State::MigrationHangingUp) && (state != State::MigrationHangingUp)
&& (state != State::Ended) && (state != State::Ended)
&& (state != State::EndedByOtherDevice) && (state != State::EndedByOtherDevice)
&& (state != State::FailedHangingUp) && (state != State::FailedHangingUp)
&& (state != State::Failed)) { && (state != State::Failed)) {
const auto isBusy = (state == State::Busy);
const auto isWaitingUser = (state == State::WaitingUserConfirmation);
if (isBusy) {
_powerSaveBlocker = nullptr;
}
if (_startVideo && !isWaitingUser) { if (_startVideo && !isWaitingUser) {
_startVideo = nullptr; _startVideo = nullptr;
} else if (!_startVideo && isWaitingUser) { } else if (!_startVideo && isWaitingUser) {
@ -1472,7 +1347,7 @@ void Panel::stateChanged(State state) {
refreshAnswerHangupRedialLabel(); refreshAnswerHangupRedialLabel();
} }
if (!_call->isKeyShaForFingerprintReady()) { if (!_call->isKeyShaForFingerprintReady()) {
_fingerprint.destroy(); _fingerprint = nullptr;
} else if (!_fingerprint) { } else if (!_fingerprint) {
_fingerprint = CreateFingerprintAndSignalBars(widget(), _call); _fingerprint = CreateFingerprintAndSignalBars(widget(), _call);
updateControlsGeometry(); updateControlsGeometry();

View file

@ -7,14 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/weak_ptr.h"
#include "base/timer.h"
#include "base/object_ptr.h"
#include "base/unique_qptr.h"
#include "calls/calls_call.h" #include "calls/calls_call.h"
#include "calls/group/ui/desktop_capture_choose_source.h" #include "calls/group/ui/desktop_capture_choose_source.h"
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/gl/gl_window.h"
#include "ui/rp_widget.h" #include "ui/rp_widget.h"
class Image; class Image;
@ -32,6 +27,7 @@ class SessionShow;
} // namespace Main } // namespace Main
namespace Ui { namespace Ui {
class Show;
class BoxContent; class BoxContent;
class LayerWidget; class LayerWidget;
enum class LayerOption; enum class LayerOption;
@ -64,6 +60,7 @@ struct CallBodyLayout;
namespace Calls { namespace Calls {
class Window;
class Userpic; class Userpic;
class SignalBars; class SignalBars;
class VideoBubble; class VideoBubble;
@ -84,32 +81,11 @@ public:
[[nodiscard]] ConferencePanelMigration migrationInfo() const; [[nodiscard]] ConferencePanelMigration migrationInfo() const;
base::weak_ptr<Ui::Toast::Instance> showToast(
const QString &text,
crl::time duration = 0);
base::weak_ptr<Ui::Toast::Instance> showToast(
TextWithEntities &&text,
crl::time duration = 0);
base::weak_ptr<Ui::Toast::Instance> showToast(
Ui::Toast::Config &&config);
void showBox(object_ptr<Ui::BoxContent> box);
void showBox(
object_ptr<Ui::BoxContent> box,
Ui::LayerOptions options,
anim::type animated = anim::type::normal);
void showLayer(
std::unique_ptr<Ui::LayerWidget> layer,
Ui::LayerOptions options,
anim::type animated = anim::type::normal);
void hideLayer(anim::type animated = anim::type::normal);
[[nodiscard]] bool isLayerShown() const;
void showAndActivate(); void showAndActivate();
void minimize(); void minimize();
void toggleFullScreen(); void toggleFullScreen();
void replaceCall(not_null<Call*> call); void replaceCall(not_null<Call*> call);
void closeBeforeDestroy(); void closeBeforeDestroy(bool windowIsReused = false);
QWidget *chooseSourceParent() override; QWidget *chooseSourceParent() override;
QString chooseSourceActiveDeviceId() override; QString chooseSourceActiveDeviceId() override;
@ -123,7 +99,10 @@ public:
[[nodiscard]] rpl::producer<bool> startOutgoingRequests() const; [[nodiscard]] rpl::producer<bool> startOutgoingRequests() const;
[[nodiscard]] std::shared_ptr<Main::SessionShow> uiShow(); [[nodiscard]] std::shared_ptr<Main::SessionShow> sessionShow();
[[nodiscard]] std::shared_ptr<Ui::Show> uiShow();
[[nodiscard]] not_null<Ui::RpWindow*> window() const;
[[nodiscard]] rpl::lifetime &lifetime(); [[nodiscard]] rpl::lifetime &lifetime();
@ -138,8 +117,6 @@ private:
StartCall, StartCall,
}; };
[[nodiscard]] not_null<Ui::RpWindow*> window() const;
void paint(QRect clip); void paint(QRect clip);
void initWindow(); void initWindow();
@ -184,43 +161,35 @@ private:
Call *_call = nullptr; Call *_call = nullptr;
not_null<UserData*> _user; not_null<UserData*> _user;
Ui::GL::Window _window; std::shared_ptr<Window> _window;
const std::unique_ptr<Ui::LayerManager> _layerBg;
std::unique_ptr<Incoming> _incoming; std::unique_ptr<Incoming> _incoming;
#ifndef Q_OS_MAC
std::unique_ptr<Ui::Platform::SeparateTitleControls> _controls;
#endif // !Q_OS_MAC
std::unique_ptr<base::PowerSaveBlocker> _powerSaveBlocker;
QSize _incomingFrameSize; QSize _incomingFrameSize;
rpl::lifetime _callLifetime; rpl::lifetime _callLifetime;
not_null<const style::CallBodyLayout*> _bodySt; not_null<const style::CallBodyLayout*> _bodySt;
object_ptr<Ui::CallButton> _answerHangupRedial; base::unique_qptr<Ui::CallButton> _answerHangupRedial;
object_ptr<Ui::FadeWrap<Ui::CallButton>> _decline; base::unique_qptr<Ui::FadeWrap<Ui::CallButton>> _decline;
object_ptr<Ui::FadeWrap<Ui::CallButton>> _cancel; base::unique_qptr<Ui::FadeWrap<Ui::CallButton>> _cancel;
bool _hangupShown = false; bool _hangupShown = false;
bool _conferenceSupported = false; bool _conferenceSupported = 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<Ui::FadeWrap<Ui::CallButton>> _screencast; base::unique_qptr<Ui::FadeWrap<Ui::CallButton>> _screencast;
object_ptr<Ui::CallButton> _camera; base::unique_qptr<Ui::CallButton> _camera;
Ui::CallButton *_cameraDeviceToggle = nullptr; Ui::CallButton *_cameraDeviceToggle = nullptr;
base::unique_qptr<Ui::CallButton> _startVideo; base::unique_qptr<Ui::CallButton> _startVideo;
object_ptr<Ui::FadeWrap<Ui::CallButton>> _mute; base::unique_qptr<Ui::FadeWrap<Ui::CallButton>> _mute;
Ui::CallButton *_audioDeviceToggle = nullptr; Ui::CallButton *_audioDeviceToggle = nullptr;
object_ptr < Ui::FadeWrap<Ui::CallButton>> _addPeople; base::unique_qptr<Ui::FadeWrap<Ui::CallButton>> _addPeople;
object_ptr<Ui::FlatLabel> _name; base::unique_qptr<Ui::FlatLabel> _name;
object_ptr<Ui::FlatLabel> _status; base::unique_qptr<Ui::FlatLabel> _status;
object_ptr<Ui::RpWidget> _conferenceParticipants = { nullptr }; base::unique_qptr<Ui::RpWidget> _conferenceParticipants;
object_ptr<Ui::RpWidget> _fingerprint = { nullptr }; base::unique_qptr<Ui::RpWidget> _fingerprint;
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteAudioMute = { nullptr }; base::unique_qptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteAudioMute;
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteLowBattery base::unique_qptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteLowBattery;
= { nullptr };
std::unique_ptr<Userpic> _userpic; std::unique_ptr<Userpic> _userpic;
std::unique_ptr<VideoBubble> _outgoingVideoBubble; std::unique_ptr<VideoBubble> _outgoingVideoBubble;
QPixmap _bottomShadow; QPixmap _bottomShadow;
@ -245,6 +214,8 @@ private:
rpl::event_stream<bool> _startOutgoingRequests; rpl::event_stream<bool> _startOutgoingRequests;
rpl::lifetime _lifetime;
}; };
} // namespace Calls } // namespace Calls

View file

@ -0,0 +1,250 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "calls/calls_window.h"
#include "base/power_save_blocker.h"
#include "ui/platform/ui_platform_window_title.h"
#include "ui/widgets/rp_window.h"
#include "ui/layers/layer_manager.h"
#include "ui/layers/show.h"
#include "styles/style_calls.h"
namespace Calls {
namespace {
class Show final : public Ui::Show {
public:
explicit Show(not_null<Window*> window);
~Show();
void showOrHideBoxOrLayer(
std::variant<
v::null_t,
object_ptr<Ui::BoxContent>,
std::unique_ptr<Ui::LayerWidget>> &&layer,
Ui::LayerOptions options,
anim::type animated) const override;
[[nodiscard]] not_null<QWidget*> toastParent() const override;
[[nodiscard]] bool valid() const override;
operator bool() const override;
private:
const base::weak_ptr<Window> _window;
};
Show::Show(not_null<Window*> window)
: _window(base::make_weak(window)) {
}
Show::~Show() = default;
void Show::showOrHideBoxOrLayer(
std::variant<
v::null_t,
object_ptr<Ui::BoxContent>,
std::unique_ptr<Ui::LayerWidget>> &&layer,
Ui::LayerOptions options,
anim::type animated) const {
using UniqueLayer = std::unique_ptr<Ui::LayerWidget>;
using ObjectBox = object_ptr<Ui::BoxContent>;
if (auto layerWidget = std::get_if<UniqueLayer>(&layer)) {
if (const auto window = _window.get()) {
window->showLayer(std::move(*layerWidget), options, animated);
}
} else if (auto box = std::get_if<ObjectBox>(&layer)) {
if (const auto window = _window.get()) {
window->showBox(std::move(*box), options, animated);
}
} else if (const auto window = _window.get()) {
window->hideLayer(animated);
}
}
not_null<QWidget*> Show::toastParent() const {
const auto window = _window.get();
Assert(window != nullptr);
return window->widget();
}
bool Show::valid() const {
return !_window.empty();
}
Show::operator bool() const {
return valid();
}
} // namespace
Window::Window()
: _layerBg(std::make_unique<Ui::LayerManager>(widget()))
#ifndef Q_OS_MAC
, _controls(Ui::Platform::SetupSeparateTitleControls(
window(),
st::callTitle,
[=](bool maximized) { _maximizeRequests.fire_copy(maximized); },
_controlsTop.value()))
#endif // !Q_OS_MAC
{
_layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox);
_layerBg->setHideByBackgroundClick(true);
}
Window::~Window() = default;
Ui::GL::Backend Window::backend() const {
return _window.backend();
}
not_null<Ui::RpWindow*> Window::window() const {
return _window.window();
}
not_null<Ui::RpWidget*> Window::widget() const {
return _window.widget();
}
void Window::raiseControls() {
#ifndef Q_OS_MAC
_controls->wrap.raise();
#endif // !Q_OS_MAC
}
void Window::setControlsStyle(const style::WindowTitle &st) {
#ifndef Q_OS_MAC
_controls->controls.setStyle(st);
#endif // Q_OS_MAC
}
void Window::setControlsShown(float64 shown) {
#ifndef Q_OS_MAC
_controlsTop = anim::interpolate(-_controls->wrap.height(), 0, shown);
#endif // Q_OS_MAC
}
int Window::controlsWrapTop() const {
#ifndef Q_OS_MAC
return _controls->wrap.y();
#else // Q_OS_MAC
return 0;
#endif // Q_OS_MAC
}
QRect Window::controlsGeometry() const {
#ifndef Q_OS_MAC
return _controls->controls.geometry();
#else // Q_OS_MAC
return QRect();
#endif // Q_OS_MAC
}
auto Window::controlsLayoutChanges() const
-> rpl::producer<Ui::Platform::TitleLayout> {
#ifndef Q_OS_MAC
return _controls->controls.layout().changes();
#else // Q_OS_MAC
return rpl::never<Ui::Platform::TitleLayout>();
#endif // Q_OS_MAC
}
bool Window::controlsHasHitTest(QPoint widgetPoint) const {
#ifndef Q_OS_MAC
using Result = Ui::Platform::HitTestResult;
const auto windowPoint = widget()->mapTo(window(), widgetPoint);
return (_controls->controls.hitTest(windowPoint) != Result::None);
#else // Q_OS_MAC
return false;
#endif // Q_OS_MAC
}
rpl::producer<bool> Window::maximizeRequests() const {
return _maximizeRequests.events();
}
base::weak_ptr<Ui::Toast::Instance> Window::showToast(
const QString &text,
crl::time duration) {
return Show(this).showToast(text, duration);
}
base::weak_ptr<Ui::Toast::Instance> Window::showToast(
TextWithEntities &&text,
crl::time duration) {
return Show(this).showToast(std::move(text), duration);
}
base::weak_ptr<Ui::Toast::Instance> Window::showToast(
Ui::Toast::Config &&config) {
return Show(this).showToast(std::move(config));
}
void Window::raiseLayers() {
_layerBg->raise();
}
const Ui::LayerWidget *Window::topShownLayer() const {
return _layerBg->topShownLayer();
}
void Window::showBox(object_ptr<Ui::BoxContent> box) {
showBox(std::move(box), Ui::LayerOption::KeepOther, anim::type::normal);
}
void Window::showBox(
object_ptr<Ui::BoxContent> box,
Ui::LayerOptions options,
anim::type animated) {
_showingLayer.fire({});
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);
}
void Window::showLayer(
std::unique_ptr<Ui::LayerWidget> layer,
Ui::LayerOptions options,
anim::type animated) {
_showingLayer.fire({});
if (window()->width() < st::groupCallWidth
|| window()->height() < st::groupCallWidth) {
window()->resize(
std::max(window()->width(), st::groupCallWidth),
std::max(window()->height(), st::groupCallWidth));
}
_layerBg->showLayer(std::move(layer), options, animated);
}
void Window::hideLayer(anim::type animated) {
_layerBg->hideAll(animated);
}
bool Window::isLayerShown() const {
return _layerBg->topShownLayer() != nullptr;
}
std::shared_ptr<Ui::Show> Window::uiShow() {
return std::make_shared<Show>(this);
}
void Window::togglePowerSaveBlocker(bool enabled) {
if (!enabled) {
_powerSaveBlocker = nullptr;
} else if (!_powerSaveBlocker) {
_powerSaveBlocker = std::make_unique<base::PowerSaveBlocker>(
base::PowerSaveBlockType::PreventDisplaySleep,
u"Video call is active"_q,
window()->windowHandle());
}
}
} // namespace Calls

View file

@ -0,0 +1,112 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/object_ptr.h"
#include "ui/effects/animations.h"
#include "ui/gl/gl_window.h"
namespace base {
class PowerSaveBlocker;
} // namespace base
namespace style {
struct WindowTitle;
} // namespace style
namespace Ui {
class BoxContent;
class RpWindow;
class RpWidget;
class LayerManager;
class LayerWidget;
enum class LayerOption;
using LayerOptions = base::flags<LayerOption>;
class Show;
} // namespace Ui
namespace Ui::Platform {
struct SeparateTitleControls;
struct TitleLayout;
} // namespace Ui::Platform
namespace Ui::Toast {
struct Config;
class Instance;
} // namespace Ui::Toast
namespace Calls {
class Window final : public base::has_weak_ptr {
public:
Window();
~Window();
[[nodiscard]] Ui::GL::Backend backend() const;
[[nodiscard]] not_null<Ui::RpWindow*> window() const;
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
void raiseControls();
void setControlsStyle(const style::WindowTitle &st);
void setControlsShown(float64 shown);
[[nodiscard]] int controlsWrapTop() const;
[[nodiscard]] QRect controlsGeometry() const;
[[nodiscard]] auto controlsLayoutChanges() const
-> rpl::producer<Ui::Platform::TitleLayout>;
[[nodiscard]] bool controlsHasHitTest(QPoint widgetPoint) const;
[[nodiscard]] rpl::producer<bool> maximizeRequests() const;
void raiseLayers();
[[nodiscard]] const Ui::LayerWidget *topShownLayer() const;
base::weak_ptr<Ui::Toast::Instance> showToast(
const QString &text,
crl::time duration = 0);
base::weak_ptr<Ui::Toast::Instance> showToast(
TextWithEntities &&text,
crl::time duration = 0);
base::weak_ptr<Ui::Toast::Instance> showToast(
Ui::Toast::Config &&config);
void showBox(object_ptr<Ui::BoxContent> box);
void showBox(
object_ptr<Ui::BoxContent> box,
Ui::LayerOptions options,
anim::type animated = anim::type::normal);
void showLayer(
std::unique_ptr<Ui::LayerWidget> layer,
Ui::LayerOptions options,
anim::type animated = anim::type::normal);
void hideLayer(anim::type animated = anim::type::normal);
[[nodiscard]] bool isLayerShown() const;
[[nodiscard]] rpl::producer<> showingLayer() const {
return _showingLayer.events();
}
[[nodiscard]] std::shared_ptr<Ui::Show> uiShow();
void togglePowerSaveBlocker(bool enabled);
private:
Ui::GL::Window _window;
const std::unique_ptr<Ui::LayerManager> _layerBg;
#ifndef Q_OS_MAC
rpl::variable<int> _controlsTop = 0;
const std::unique_ptr<Ui::Platform::SeparateTitleControls> _controls;
#endif // !Q_OS_MAC
std::unique_ptr<base::PowerSaveBlocker> _powerSaveBlocker;
rpl::event_stream<bool> _maximizeRequests;
rpl::event_stream<> _showingLayer;
};
} // namespace Calls

View file

@ -48,6 +48,8 @@ class SessionController;
namespace Calls { namespace Calls {
class Window;
struct InviteRequest { struct InviteRequest {
not_null<UserData*> user; not_null<UserData*> user;
bool video = false; bool video = false;
@ -75,8 +77,7 @@ struct StartConferenceInfo {
}; };
struct ConferencePanelMigration { struct ConferencePanelMigration {
QScreen *screen = nullptr; std::shared_ptr<Window> window;
QRect geometry;
}; };
} // namespace Calls } // namespace Calls

View file

@ -1359,22 +1359,22 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
window->invokeForSessionController( window->invokeForSessionController(
account, account,
participantPeer, participantPeer,
[&](not_null<Window::SessionController*> newController) { [&](not_null<::Window::SessionController*> newController) {
callback(newController); callback(newController);
newController->widget()->activate(); newController->widget()->activate();
}); });
} }
}; };
const auto showProfile = [=] { const auto showProfile = [=] {
withActiveWindow([=](not_null<Window::SessionController*> window) { withActiveWindow([=](not_null<::Window::SessionController*> window) {
window->showPeerInfo(participantPeer); window->showPeerInfo(participantPeer);
}); });
}; };
const auto showHistory = [=] { const auto showHistory = [=] {
withActiveWindow([=](not_null<Window::SessionController*> window) { withActiveWindow([=](not_null<::Window::SessionController*> window) {
window->showPeerHistory( window->showPeerHistory(
participantPeer, participantPeer,
Window::SectionShow::Way::Forward); ::Window::SectionShow::Way::Forward);
}); });
}; };
const auto removeFromVoiceChat = crl::guard(this, [=] { const auto removeFromVoiceChat = crl::guard(this, [=] {

View file

@ -17,7 +17,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/group/ui/calls_group_scheduled_labels.h" #include "calls/group/ui/calls_group_scheduled_labels.h"
#include "calls/group/ui/desktop_capture_choose_source.h" #include "calls/group/ui/desktop_capture_choose_source.h"
#include "calls/calls_emoji_fingerprint.h" #include "calls/calls_emoji_fingerprint.h"
#include "ui/platform/ui_platform_window_title.h" #include "calls/calls_window.h"
#include "ui/platform/ui_platform_window_title.h" // TitleLayout
#include "ui/platform/ui_platform_utility.h" #include "ui/platform/ui_platform_utility.h"
#include "ui/controls/call_mute_button.h" #include "ui/controls/call_mute_button.h"
#include "ui/widgets/buttons.h" #include "ui/widgets/buttons.h"
@ -29,7 +30,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/rp_window.h" #include "ui/widgets/rp_window.h"
#include "ui/chat/group_call_bar.h" #include "ui/chat/group_call_bar.h"
#include "ui/controls/userpic_button.h" #include "ui/controls/userpic_button.h"
#include "ui/layers/layer_manager.h"
#include "ui/layers/generic_box.h" #include "ui/layers/generic_box.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
@ -54,7 +54,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/unixtime.h" #include "base/unixtime.h"
#include "base/qt_signal_producer.h" #include "base/qt_signal_producer.h"
#include "base/timer_rpl.h" #include "base/timer_rpl.h"
#include "base/power_save_blocker.h"
#include "apiwrap.h" // api().kick. #include "apiwrap.h" // api().kick.
#include "api/api_chat_participants.h" // api().kick. #include "api/api_chat_participants.h" // api().kick.
#include "webrtc/webrtc_environment.h" #include "webrtc/webrtc_environment.h"
@ -91,77 +90,6 @@ constexpr auto kHideControlsTimeout = 5 * crl::time(1000);
return result; return result;
} }
class Show final : public Main::SessionShow {
public:
explicit Show(not_null<Panel*> panel);
~Show();
void showOrHideBoxOrLayer(
std::variant<
v::null_t,
object_ptr<Ui::BoxContent>,
std::unique_ptr<Ui::LayerWidget>> &&layer,
Ui::LayerOptions options,
anim::type animated) const override;
[[nodiscard]] not_null<QWidget*> toastParent() const override;
[[nodiscard]] bool valid() const override;
operator bool() const override;
[[nodiscard]] Main::Session &session() const override;
private:
const base::weak_ptr<Panel> _panel;
};
Show::Show(not_null<Panel*> panel)
: _panel(base::make_weak(panel)) {
}
Show::~Show() = default;
void Show::showOrHideBoxOrLayer(
std::variant<
v::null_t,
object_ptr<Ui::BoxContent>,
std::unique_ptr<Ui::LayerWidget>> &&layer,
Ui::LayerOptions options,
anim::type animated) const {
using UniqueLayer = std::unique_ptr<Ui::LayerWidget>;
using ObjectBox = object_ptr<Ui::BoxContent>;
if (auto layerWidget = std::get_if<UniqueLayer>(&layer)) {
if (const auto panel = _panel.get()) {
panel->showLayer(std::move(*layerWidget), options, animated);
}
} else if (auto box = std::get_if<ObjectBox>(&layer)) {
if (const auto panel = _panel.get()) {
panel->showBox(std::move(*box), options, animated);
}
} else if (const auto panel = _panel.get()) {
panel->hideLayer(animated);
}
}
not_null<QWidget*> Show::toastParent() const {
const auto panel = _panel.get();
Assert(panel != nullptr);
return panel->widget();
}
bool Show::valid() const {
return !_panel.empty();
}
Show::operator bool() const {
return valid();
}
Main::Session &Show::session() const {
const auto panel = _panel.get();
Assert(panel != nullptr);
return panel->call()->peer()->session();
}
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
void UnpinMaximized(not_null<QWidget*> widget) { void UnpinMaximized(not_null<QWidget*> widget) {
SetWindowPos( SetWindowPos(
@ -198,20 +126,12 @@ Panel::Panel(not_null<GroupCall*> call)
Panel::Panel(not_null<GroupCall*> call, ConferencePanelMigration info) Panel::Panel(not_null<GroupCall*> call, ConferencePanelMigration info)
: _call(call) : _call(call)
, _peer(call->peer()) , _peer(call->peer())
, _layerBg(std::make_unique<Ui::LayerManager>(widget())) , _window(info.window ? info.window : std::make_shared<Window>())
#ifndef Q_OS_MAC
, _controls(Ui::Platform::SetupSeparateTitleControls(
window(),
st::groupCallTitle,
nullptr,
_controlsTop.value()))
#endif // !Q_OS_MAC
, _powerSaveBlocker(std::make_unique<base::PowerSaveBlocker>(
base::PowerSaveBlockType::PreventDisplaySleep,
u"Video chat is active"_q,
window()->windowHandle()))
, _viewport( , _viewport(
std::make_unique<Viewport>(widget(), PanelMode::Wide, _window.backend())) std::make_unique<Viewport>(
widget(),
PanelMode::Wide,
_window->backend()))
, _mute(std::make_unique<Ui::CallMuteButton>( , _mute(std::make_unique<Ui::CallMuteButton>(
widget(), widget(),
st::callMuteButton, st::callMuteButton,
@ -241,9 +161,6 @@ Panel::Panel(not_null<GroupCall*> call, ConferencePanelMigration info)
return result; return result;
}) })
, _hideControlsTimer([=] { toggleWideControls(false); }) { , _hideControlsTimer([=] { toggleWideControls(false); }) {
_layerBg->setStyleOverrides(&st::groupCallBox, &st::groupCallLayerBox);
_layerBg->setHideByBackgroundClick(true);
_viewport->widget()->hide(); _viewport->widget()->hide();
if (!_viewport->requireARGB32()) { if (!_viewport->requireARGB32()) {
_call->setNotRequireARGB32(); _call->setNotRequireARGB32();
@ -287,25 +204,12 @@ bool Panel::isActive() const {
return window()->isActiveWindow() && isVisible(); return window()->isActiveWindow() && isVisible();
} }
base::weak_ptr<Ui::Toast::Instance> Panel::showToast( std::shared_ptr<Main::SessionShow> Panel::sessionShow() {
const QString &text, return Main::MakeSessionShow(uiShow(), &_peer->session());
crl::time duration) {
return Show(this).showToast(text, duration);
} }
base::weak_ptr<Ui::Toast::Instance> Panel::showToast( std::shared_ptr<Ui::Show> Panel::uiShow() {
TextWithEntities &&text, return _window->uiShow();
crl::time duration) {
return Show(this).showToast(std::move(text), duration);
}
base::weak_ptr<Ui::Toast::Instance> Panel::showToast(
Ui::Toast::Config &&config) {
return Show(this).showToast(std::move(config));
}
std::shared_ptr<Main::SessionShow> Panel::uiShow() {
return std::make_shared<Show>(this);
} }
void Panel::minimize() { void Panel::minimize() {
@ -394,12 +298,20 @@ void Panel::initWindow() {
subscribeToPeerChanges(); subscribeToPeerChanges();
} }
const auto updateFullScreen = [=] {
const auto state = window()->windowState();
const auto full = (state & Qt::WindowFullScreen)
|| (state & Qt::WindowMaximized);
_rtmpFull = _call->rtmp() && full;
_fullScreenOrMaximized = full;
};
base::install_event_filter(window().get(), [=](not_null<QEvent*> e) { base::install_event_filter(window().get(), [=](not_null<QEvent*> e) {
if (e->type() == QEvent::Close && handleClose()) { const auto type = e->type();
if (type == QEvent::Close && handleClose()) {
e->ignore(); e->ignore();
return base::EventFilterResult::Cancel; return base::EventFilterResult::Cancel;
} else if (e->type() == QEvent::KeyPress } else if (_call->rtmp()
|| e->type() == QEvent::KeyRelease) { && (type == QEvent::KeyPress || type == QEvent::KeyRelease)) {
const auto key = static_cast<QKeyEvent*>(e.get())->key(); const auto key = static_cast<QKeyEvent*>(e.get())->key();
if (key == Qt::Key_Space) { if (key == Qt::Key_Space) {
_call->pushToTalk( _call->pushToTalk(
@ -409,16 +321,19 @@ void Panel::initWindow() {
&& _fullScreenOrMaximized.current()) { && _fullScreenOrMaximized.current()) {
toggleFullScreen(); toggleFullScreen();
} }
} else if (e->type() == QEvent::WindowStateChange && _call->rtmp()) { } else if (type == QEvent::WindowStateChange) {
const auto state = window()->windowState(); updateFullScreen();
_fullScreenOrMaximized = (state & Qt::WindowFullScreen)
|| (state & Qt::WindowMaximized);
} }
return base::EventFilterResult::Continue; return base::EventFilterResult::Continue;
}); }, lifetime());
updateFullScreen();
const auto guard = base::make_weak(this);
window()->setBodyTitleArea([=](QPoint widgetPoint) { window()->setBodyTitleArea([=](QPoint widgetPoint) {
using Flag = Ui::WindowTitleHitTestFlag; using Flag = Ui::WindowTitleHitTestFlag;
if (!guard) {
return (Flag::None | Flag(0));
}
const auto titleRect = QRect( const auto titleRect = QRect(
0, 0,
0, 0,
@ -434,7 +349,7 @@ void Panel::initWindow() {
if (!moveable) { if (!moveable) {
return (Flag::None | Flag(0)); return (Flag::None | Flag(0));
} }
const auto shown = _layerBg->topShownLayer(); const auto shown = _window->topShownLayer();
return (!shown || !shown->geometry().contains(widgetPoint)) return (!shown || !shown->geometry().contains(widgetPoint))
? (Flag::Move | Flag::Menu | Flag::Maximize) ? (Flag::Move | Flag::Menu | Flag::Maximize)
: Flag::None; : Flag::None;
@ -444,6 +359,23 @@ void Panel::initWindow() {
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
updateMode(); updateMode();
}, lifetime()); }, lifetime());
_window->maximizeRequests() | rpl::start_with_next([=](bool maximized) {
if (_call->rtmp()) {
toggleFullScreen(maximized);
} else {
window()->setWindowState(maximized
? Qt::WindowMaximized
: Qt::WindowNoState);
}
}, lifetime());
_window->showingLayer() | rpl::start_with_next([=] {
hideStickedTooltip(StickedTooltipHide::Unavailable);
}, lifetime());
_window->setControlsStyle(st::groupCallTitle);
_window->togglePowerSaveBlocker(true);
} }
void Panel::initWidget() { void Panel::initWidget() {
@ -462,7 +394,7 @@ void Panel::initWidget() {
// some geometries depends on _controls->controls.geometry, // some geometries depends on _controls->controls.geometry,
// which is not updated here yet. // which is not updated here yet.
crl::on_main(widget(), [=] { updateControlsGeometry(); }); crl::on_main(this, [=] { updateControlsGeometry(); });
}, lifetime()); }, lifetime());
} }
@ -471,7 +403,7 @@ void Panel::endCall() {
_call->hangup(); _call->hangup();
return; return;
} }
showBox(Box( uiShow()->showBox(Box(
LeaveBox, LeaveBox,
_call, _call,
false, false,
@ -501,7 +433,7 @@ void Panel::startScheduledNow() {
.confirmText = tr::lng_group_call_start_now(), .confirmText = tr::lng_group_call_start_now(),
}); });
*box = owned.data(); *box = owned.data();
showBox(std::move(owned)); uiShow()->showBox(std::move(owned));
} }
} }
@ -608,10 +540,15 @@ void Panel::initControls() {
} }
void Panel::toggleFullScreen() { void Panel::toggleFullScreen() {
if (_fullScreenOrMaximized.current() || window()->isFullScreen()) { toggleFullScreen(
window()->showNormal(); !_fullScreenOrMaximized.current() && !window()->isFullScreen());
} else { }
void Panel::toggleFullScreen(bool fullscreen) {
if (fullscreen) {
window()->showFullScreen(); window()->showFullScreen();
} else {
window()->showNormal();
} }
} }
@ -630,7 +567,7 @@ void Panel::refreshLeftButton() {
_callShare.destroy(); _callShare.destroy();
_settings.create(widget(), st::groupCallSettings); _settings.create(widget(), st::groupCallSettings);
_settings->setClickedCallback([=] { _settings->setClickedCallback([=] {
showBox(Box(SettingsBox, _call)); uiShow()->showBox(Box(SettingsBox, _call));
}); });
trackControls(_trackControls, true); trackControls(_trackControls, true);
} }
@ -915,13 +852,13 @@ void Panel::setupMembers() {
_countdown.destroy(); _countdown.destroy();
_startsWhen.destroy(); _startsWhen.destroy();
_members.create(widget(), _call, mode(), _window.backend()); _members.create(widget(), _call, mode(), _window->backend());
setupVideo(_viewport.get()); setupVideo(_viewport.get());
setupVideo(_members->viewport()); setupVideo(_members->viewport());
_viewport->mouseInsideValue( _viewport->mouseInsideValue(
) | rpl::filter([=] { ) | rpl::filter([=] {
return !_fullScreenOrMaximized.current(); return !_rtmpFull;
}) | rpl::start_with_next([=](bool inside) { }) | rpl::start_with_next([=](bool inside) {
toggleWideControls(inside); toggleWideControls(inside);
}, _viewport->lifetime()); }, _viewport->lifetime());
@ -996,7 +933,7 @@ Fn<void(Fn<void(bool)> finished)> Panel::shareConferenceLinkCallback() {
onstack(!link.isEmpty()); onstack(!link.isEmpty());
} }
}; };
ExportConferenceCallLink(uiShow(), _call->conferenceCall(), { ExportConferenceCallLink(sessionShow(), _call->conferenceCall(), {
.finished = done, .finished = done,
.st = DarkConferenceCallLinkStyle(), .st = DarkConferenceCallLinkStyle(),
}); });
@ -1004,8 +941,9 @@ Fn<void(Fn<void(bool)> finished)> Panel::shareConferenceLinkCallback() {
} }
void Panel::migrationShowShareLink() { void Panel::migrationShowShareLink() {
uiShow()->hideLayer(anim::type::instant);
ShowConferenceCallLinkBox( ShowConferenceCallLinkBox(
uiShow(), sessionShow(),
_call->conferenceCall(), _call->conferenceCall(),
_call->existingConferenceLink(), _call->existingConferenceLink(),
{ .st = DarkConferenceCallLinkStyle() }); { .st = DarkConferenceCallLinkStyle() });
@ -1013,7 +951,7 @@ void Panel::migrationShowShareLink() {
void Panel::migrationInviteUsers(std::vector<InviteRequest> users) { void Panel::migrationInviteUsers(std::vector<InviteRequest> users) {
const auto done = [=](InviteResult result) { const auto done = [=](InviteResult result) {
showToast({ ComposeInviteResultToast(result) }); uiShow()->showToast({ ComposeInviteResultToast(result) });
}; };
_call->inviteUsers(std::move(users), crl::guard(this, done)); _call->inviteUsers(std::move(users), crl::guard(this, done));
} }
@ -1100,7 +1038,7 @@ void Panel::raiseControls() {
if (_pinOnTop) { if (_pinOnTop) {
_pinOnTop->raise(); _pinOnTop->raise();
} }
_layerBg->raise(); _window->raiseLayers();
if (_niceTooltip) { if (_niceTooltip) {
_niceTooltip->raise(); _niceTooltip->raise();
} }
@ -1178,7 +1116,7 @@ void Panel::toggleWideControls(bool shown) {
return; return;
} }
_showWideControls = shown; _showWideControls = shown;
crl::on_main(widget(), [=] { crl::on_main(this, [=] {
updateWideControlsVisibility(); updateWideControlsVisibility();
}); });
} }
@ -1189,7 +1127,7 @@ void Panel::updateWideControlsVisibility() {
if (_wideControlsShown == shown) { if (_wideControlsShown == shown) {
return; return;
} }
_viewport->setCursorShown(!_fullScreenOrMaximized.current() || shown); _viewport->setCursorShown(!_rtmpFull || shown);
_wideControlsShown = shown; _wideControlsShown = shown;
_wideControlsAnimation.start( _wideControlsAnimation.start(
[=] { updateButtonsGeometry(); }, [=] { updateButtonsGeometry(); },
@ -1216,7 +1154,7 @@ void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
const auto skip = st::groupCallRecordingMarkSkip; const auto skip = st::groupCallRecordingMarkSkip;
_recordingMark->resize(size + 2 * skip, size + 2 * skip); _recordingMark->resize(size + 2 * skip, size + 2 * skip);
_recordingMark->setClickedCallback([=] { _recordingMark->setClickedCallback([=] {
showToast({ (livestream uiShow()->showToast({ (livestream
? tr::lng_group_call_is_recorded_channel ? tr::lng_group_call_is_recorded_channel
: real->recordVideo() : real->recordVideo()
? tr::lng_group_call_is_recorded_video ? tr::lng_group_call_is_recorded_video
@ -1262,7 +1200,7 @@ void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
*startedAsVideo = isVideo; *startedAsVideo = isVideo;
} }
validateRecordingMark(recorded); validateRecordingMark(recorded);
showToast((recorded uiShow()->showToast((recorded
? (livestream ? (livestream
? tr::lng_group_call_recording_started_channel ? tr::lng_group_call_recording_started_channel
: isVideo : isVideo
@ -1323,7 +1261,7 @@ void Panel::createPinOnTop() {
pin ? &st::groupCallPinnedOnTop : nullptr, pin ? &st::groupCallPinnedOnTop : nullptr,
pin ? &st::groupCallPinnedOnTop : nullptr); pin ? &st::groupCallPinnedOnTop : nullptr);
if (!_pinOnTop->isHidden()) { if (!_pinOnTop->isHidden()) {
showToast({ pin uiShow()->showToast({ pin
? tr::lng_group_call_pinned_on_top(tr::now) ? tr::lng_group_call_pinned_on_top(tr::now)
: tr::lng_group_call_unpinned_on_top(tr::now) }); : tr::lng_group_call_unpinned_on_top(tr::now) });
} }
@ -1331,11 +1269,9 @@ void Panel::createPinOnTop() {
}; };
_fullScreenOrMaximized.value( _fullScreenOrMaximized.value(
) | rpl::start_with_next([=](bool fullScreenOrMaximized) { ) | rpl::start_with_next([=](bool fullScreenOrMaximized) {
#ifndef Q_OS_MAC _window->setControlsStyle(fullScreenOrMaximized
_controls->controls.setStyle(fullScreenOrMaximized
? st::callTitle ? st::callTitle
: st::groupCallTitle); : st::groupCallTitle);
#endif // Q_OS_MAC
_pinOnTop->setVisible(!fullScreenOrMaximized); _pinOnTop->setVisible(!fullScreenOrMaximized);
if (fullScreenOrMaximized) { if (fullScreenOrMaximized) {
@ -1425,7 +1361,7 @@ void Panel::refreshTopButton() {
void Panel::screenSharingPrivacyRequest() { void Panel::screenSharingPrivacyRequest() {
if (auto box = ScreenSharingPrivacyRequestBox()) { if (auto box = ScreenSharingPrivacyRequestBox()) {
showBox(std::move(box)); uiShow()->showBox(std::move(box));
} }
} }
@ -1476,7 +1412,7 @@ void Panel::chooseShareScreenSource() {
.confirmText = tr::lng_continue(), .confirmText = tr::lng_continue(),
}); });
*shared = box.data(); *shared = box.data();
showBox(std::move(box)); uiShow()->showBox(std::move(box));
} }
void Panel::chooseJoinAs() { void Panel::chooseJoinAs() {
@ -1487,7 +1423,7 @@ void Panel::chooseJoinAs() {
_joinAsProcess.start( _joinAsProcess.start(
_peer, _peer,
context, context,
std::make_shared<Show>(this), uiShow(),
callback, callback,
_call->joinAs()); _call->joinAs());
} }
@ -1508,7 +1444,7 @@ void Panel::showMainMenu() {
wide, wide,
[=] { chooseJoinAs(); }, [=] { chooseJoinAs(); },
[=] { chooseShareScreenSource(); }, [=] { chooseShareScreenSource(); },
[=](auto box) { showBox(std::move(box)); }); [=](auto box) { uiShow()->showBox(std::move(box)); });
if (_menu->empty()) { if (_menu->empty()) {
_wideMenuShown = false; _wideMenuShown = false;
_menu.destroy(); _menu.destroy();
@ -1574,21 +1510,21 @@ void Panel::addMembers() {
const auto conferenceLimit = appConfig.confcallSizeLimit(); const auto conferenceLimit = appConfig.confcallSizeLimit();
if (_call->conference() if (_call->conference()
&& _call->conferenceCall()->fullCount() >= conferenceLimit) { && _call->conferenceCall()->fullCount() >= conferenceLimit) {
showToast({ tr::lng_group_call_invite_limit(tr::now) }); uiShow()->showToast({ tr::lng_group_call_invite_limit(tr::now) });
} }
const auto showToastCallback = [=](TextWithEntities &&text) { const auto showToastCallback = [=](TextWithEntities &&text) {
showToast(std::move(text)); uiShow()->showToast(std::move(text));
}; };
const auto link = _call->conference() const auto link = _call->conference()
? shareConferenceLinkCallback() ? shareConferenceLinkCallback()
: nullptr; : nullptr;
if (auto box = PrepareInviteBox(_call, showToastCallback, link)) { if (auto box = PrepareInviteBox(_call, showToastCallback, link)) {
showBox(std::move(box)); uiShow()->showBox(std::move(box));
} }
} }
void Panel::kickParticipant(not_null<PeerData*> participantPeer) { void Panel::kickParticipant(not_null<PeerData*> participantPeer) {
showBox(Box([=](not_null<Ui::GenericBox*> box) { uiShow()->showBox(Box([=](not_null<Ui::GenericBox*> box) {
box->addRow( box->addRow(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
box.get(), box.get(),
@ -1621,46 +1557,6 @@ void Panel::kickParticipant(not_null<PeerData*> participantPeer) {
})); }));
} }
void Panel::showBox(object_ptr<Ui::BoxContent> box) {
showBox(std::move(box), Ui::LayerOption::KeepOther, anim::type::normal);
}
void Panel::showBox(
object_ptr<Ui::BoxContent> box,
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);
}
void Panel::showLayer(
std::unique_ptr<Ui::LayerWidget> layer,
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->showLayer(std::move(layer), options, animated);
}
void Panel::hideLayer(anim::type animated) {
_layerBg->hideAll(animated);
}
bool Panel::isLayerShown() const {
return _layerBg->topShownLayer() != nullptr;
}
void Panel::kickParticipantSure(not_null<PeerData*> participantPeer) { void Panel::kickParticipantSure(not_null<PeerData*> participantPeer) {
if (_call->conference()) { if (_call->conference()) {
if (const auto user = participantPeer->asUser()) { if (const auto user = participantPeer->asUser()) {
@ -1689,17 +1585,16 @@ void Panel::kickParticipantSure(not_null<PeerData*> participantPeer) {
void Panel::initLayout(ConferencePanelMigration info) { void Panel::initLayout(ConferencePanelMigration info) {
initGeometry(info); initGeometry(info);
#ifndef Q_OS_MAC _window->raiseControls();
_controls->wrap.raise();
_controls->controls.layout().changes( _window->controlsLayoutChanges(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
// _menuToggle geometry depends on _controls arrangement. // _menuToggle geometry depends on _controls arrangement.
crl::on_main(widget(), [=] { updateControlsGeometry(); }); crl::on_main(this, [=] { updateControlsGeometry(); });
}, lifetime()); }, lifetime());
raiseControls(); raiseControls();
#endif // !Q_OS_MAC updateControlsGeometry();
} }
void Panel::showControls() { void Panel::showControls() {
@ -1714,7 +1609,7 @@ void Panel::closeBeforeDestroy() {
} }
rpl::lifetime &Panel::lifetime() { rpl::lifetime &Panel::lifetime() {
return window()->lifetime(); return _lifetime;
} }
void Panel::initGeometry(ConferencePanelMigration info) { void Panel::initGeometry(ConferencePanelMigration info) {
@ -1724,15 +1619,7 @@ void Panel::initGeometry(ConferencePanelMigration info) {
const auto minHeight = _call->rtmp() const auto minHeight = _call->rtmp()
? st::groupCallHeightRtmpMin ? st::groupCallHeightRtmpMin
: st::groupCallHeight; : st::groupCallHeight;
if (info.screen && !info.geometry.isEmpty()) { if (!info.window) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
window()->setScreen(info.screen);
#else // Qt >= 6.0.0
window()->createWinId();
window()->windowHandle()->setScreen(info.screen);
#endif // Qt < 6.0.0
window()->setGeometry(info.geometry);
} else {
const auto center = Core::App().getPointForCallPanelCenter(); const auto center = Core::App().getPointForCallPanelCenter();
const auto width = _call->rtmp() const auto width = _call->rtmp()
? st::groupCallWidthRtmp ? st::groupCallWidthRtmp
@ -1763,7 +1650,7 @@ QRect Panel::computeTitleRect() const {
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
return QRect(70, 0, width - remove - 70, 28); return QRect(70, 0, width - remove - 70, 28);
#else // Q_OS_MAC #else // Q_OS_MAC
const auto controls = _controls->controls.geometry(); const auto controls = _window->controlsGeometry();
const auto right = controls.x() + controls.width() + skip; const auto right = controls.x() + controls.width() + skip;
return (controls.center().x() < width / 2) return (controls.center().x() < width / 2)
? QRect(right, 0, width - right - remove, controls.height()) ? QRect(right, 0, width - right - remove, controls.height())
@ -1925,7 +1812,7 @@ void Panel::refreshControlsBackground() {
} }
void Panel::refreshTitleBackground() { void Panel::refreshTitleBackground() {
if (!_fullScreenOrMaximized.current()) { if (!_rtmpFull) {
_titleBackground.destroy(); _titleBackground.destroy();
return; return;
} else if (_titleBackground) { } else if (_titleBackground) {
@ -2070,7 +1957,7 @@ void Panel::trackControl(Ui::RpWidget *widget, rpl::lifetime &lifetime) {
} }
void Panel::trackControlOver(not_null<Ui::RpWidget*> control, bool over) { void Panel::trackControlOver(not_null<Ui::RpWidget*> control, bool over) {
if (_fullScreenOrMaximized.current()) { if (_rtmpFull) {
return; return;
} else if (_stickedTooltipClose) { } else if (_stickedTooltipClose) {
if (!over) { if (!over) {
@ -2111,7 +1998,7 @@ void Panel::showStickedTooltip() {
&& callReady && callReady
&& _mute && _mute
&& !_call->mutedByAdmin() && !_call->mutedByAdmin()
&& !_layerBg->topShownLayer()) { && !_window->topShownLayer()) {
if (_stickedTooltipClose) { if (_stickedTooltipClose) {
// Showing already. // Showing already.
return; return;
@ -2314,10 +2201,10 @@ void Panel::updateControlsGeometry() {
const auto controlsOnTheLeft = true; const auto controlsOnTheLeft = true;
const auto controlsPadding = 0; const auto controlsPadding = 0;
#else // Q_OS_MAC #else // Q_OS_MAC
const auto center = _controls->controls.geometry().center(); const auto center = _window->controlsGeometry().center();
const auto controlsOnTheLeft = center.x() const auto controlsOnTheLeft = center.x()
< widget()->width() / 2; < widget()->width() / 2;
const auto controlsPadding = _controls->wrap.y(); const auto controlsPadding = _window->controlsWrapTop();
#endif // Q_OS_MAC #endif // Q_OS_MAC
const auto menux = st::groupCallMenuTogglePosition.x(); const auto menux = st::groupCallMenuTogglePosition.x();
const auto menuy = st::groupCallMenuTogglePosition.y(); const auto menuy = st::groupCallMenuTogglePosition.y();
@ -2425,7 +2312,7 @@ void Panel::updateButtonsGeometry() {
_controlsBackgroundWide->setGeometry( _controlsBackgroundWide->setGeometry(
rect.marginsAdded(st::groupCallControlsBackMargin)); rect.marginsAdded(st::groupCallControlsBackMargin));
} }
if (_fullScreenOrMaximized.current()) { if (_rtmpFull) {
refreshTitleGeometry(); refreshTitleGeometry();
} }
} else { } else {
@ -2493,10 +2380,9 @@ void Panel::updateMembersGeometry() {
_members->setVisible(!_call->rtmp()); _members->setVisible(!_call->rtmp());
const auto desiredHeight = _members->desiredHeight(); const auto desiredHeight = _members->desiredHeight();
if (mode() == PanelMode::Wide) { if (mode() == PanelMode::Wide) {
const auto full = _fullScreenOrMaximized.current(); const auto skip = _rtmpFull ? 0 : st::groupCallNarrowSkip;
const auto skip = full ? 0 : st::groupCallNarrowSkip;
const auto membersWidth = st::groupCallNarrowMembersWidth; const auto membersWidth = st::groupCallNarrowMembersWidth;
const auto top = full ? 0 : st::groupCallWideVideoTop; const auto top = _rtmpFull ? 0 : st::groupCallWideVideoTop;
_members->setGeometry( _members->setGeometry(
widget()->width() - skip - membersWidth, widget()->width() - skip - membersWidth,
top, top,
@ -2505,7 +2391,7 @@ void Panel::updateMembersGeometry() {
const auto viewportSkip = _call->rtmp() const auto viewportSkip = _call->rtmp()
? 0 ? 0
: (skip + membersWidth); : (skip + membersWidth);
_viewport->setGeometry(full, { _viewport->setGeometry(_rtmpFull, {
skip, skip,
top, top,
widget()->width() - viewportSkip - 2 * skip, widget()->width() - viewportSkip - 2 * skip,
@ -2654,9 +2540,8 @@ void Panel::refreshTitleGeometry() {
? st::groupCallTitleTop ? st::groupCallTitleTop
: (st::groupCallWideVideoTop : (st::groupCallWideVideoTop
- st::groupCallTitleLabel.style.font->height) / 2; - st::groupCallTitleLabel.style.font->height) / 2;
const auto shown = _fullScreenOrMaximized.current() const auto shown = _rtmpFull
? _wideControlsAnimation.value( ? _wideControlsAnimation.value(_wideControlsShown ? 1. : 0.)
_wideControlsShown ? 1. : 0.)
: 1.; : 1.;
const auto top = anim::interpolate( const auto top = anim::interpolate(
-_title->height() - st::boxRadius, -_title->height() - st::boxRadius,
@ -2720,10 +2605,7 @@ void Panel::refreshTitleGeometry() {
} else { } else {
layout(left + titleRect.width() - best); layout(left + titleRect.width() - best);
} }
_window->setControlsShown(shown);
#ifndef Q_OS_MAC
_controlsTop = anim::interpolate(-_controls->wrap.height(), 0, shown);
#endif // Q_OS_MAC
} }
void Panel::refreshTitleColors() { void Panel::refreshTitleColors() {
@ -2760,11 +2642,11 @@ bool Panel::handleClose() {
} }
not_null<Ui::RpWindow*> Panel::window() const { not_null<Ui::RpWindow*> Panel::window() const {
return _window.window(); return _window->window();
} }
not_null<Ui::RpWidget*> Panel::widget() const { not_null<Ui::RpWidget*> Panel::widget() const {
return _window.widget(); return _window->widget();
} }
} // namespace Calls::Group } // namespace Calls::Group

View file

@ -7,32 +7,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#pragma once #pragma once
#include "base/weak_ptr.h"
#include "base/timer.h"
#include "base/flags.h"
#include "base/object_ptr.h" #include "base/object_ptr.h"
#include "base/unique_qptr.h"
#include "calls/group/calls_group_call.h" #include "calls/group/calls_group_call.h"
#include "calls/group/calls_group_common.h" #include "calls/group/calls_group_common.h"
#include "calls/group/calls_choose_join_as.h" #include "calls/group/calls_choose_join_as.h"
#include "calls/group/ui/desktop_capture_choose_source.h" #include "calls/group/ui/desktop_capture_choose_source.h"
#include "ui/effects/animations.h" #include "ui/effects/animations.h"
#include "ui/gl/gl_window.h"
#include "ui/layers/show.h"
#include "ui/rp_widget.h"
class Image; class Image;
namespace base {
class PowerSaveBlocker;
} // namespace base
namespace Data { namespace Data {
class PhotoMedia; class PhotoMedia;
class GroupCall; class GroupCall;
} // namespace Data } // namespace Data
namespace Main {
class SessionShow;
} // namespace Main
namespace Ui { namespace Ui {
class Show;
class BoxContent; class BoxContent;
class LayerWidget; class LayerWidget;
enum class LayerOption; enum class LayerOption;
@ -45,13 +39,13 @@ class CallMuteButton;
class IconButton; class IconButton;
class FlatLabel; class FlatLabel;
class RpWidget; class RpWidget;
class RpWindow;
template <typename Widget> template <typename Widget>
class FadeWrap; class FadeWrap;
template <typename Widget> template <typename Widget>
class PaddingWrap; class PaddingWrap;
class ScrollArea; class ScrollArea;
class GenericBox; class GenericBox;
class LayerManager;
class GroupCallScheduledLeft; class GroupCallScheduledLeft;
} // namespace Ui } // namespace Ui
@ -60,14 +54,6 @@ class Instance;
struct Config; struct Config;
} // namespace Ui::Toast } // namespace Ui::Toast
namespace Ui::Platform {
struct SeparateTitleControls;
} // namespace Ui::Platform
namespace Main {
class SessionShow;
} // namespace Main
namespace style { namespace style {
struct CallSignalBars; struct CallSignalBars;
struct CallBodyLayout; struct CallBodyLayout;
@ -76,6 +62,7 @@ struct CallBodyLayout;
namespace Calls { namespace Calls {
struct InviteRequest; struct InviteRequest;
struct ConferencePanelMigration; struct ConferencePanelMigration;
class Window;
} // namespace Calls } // namespace Calls
namespace Calls::Group { namespace Calls::Group {
@ -100,37 +87,20 @@ public:
[[nodiscard]] bool isVisible() const; [[nodiscard]] bool isVisible() const;
[[nodiscard]] bool isActive() const; [[nodiscard]] bool isActive() const;
base::weak_ptr<Ui::Toast::Instance> showToast(
const QString &text,
crl::time duration = 0);
base::weak_ptr<Ui::Toast::Instance> showToast(
TextWithEntities &&text,
crl::time duration = 0);
base::weak_ptr<Ui::Toast::Instance> showToast(
Ui::Toast::Config &&config);
void showBox(object_ptr<Ui::BoxContent> box);
void showBox(
object_ptr<Ui::BoxContent> box,
Ui::LayerOptions options,
anim::type animated = anim::type::normal);
void showLayer(
std::unique_ptr<Ui::LayerWidget> layer,
Ui::LayerOptions options,
anim::type animated = anim::type::normal);
void hideLayer(anim::type animated = anim::type::normal);
[[nodiscard]] bool isLayerShown() const;
void migrationShowShareLink(); void migrationShowShareLink();
void migrationInviteUsers(std::vector<InviteRequest> users); void migrationInviteUsers(std::vector<InviteRequest> users);
void minimize(); void minimize();
void toggleFullScreen(); void toggleFullScreen();
void toggleFullScreen(bool fullscreen);
void close(); void close();
void showAndActivate(); void showAndActivate();
void closeBeforeDestroy(); void closeBeforeDestroy();
[[nodiscard]] std::shared_ptr<Main::SessionShow> uiShow(); [[nodiscard]] std::shared_ptr<Main::SessionShow> sessionShow();
[[nodiscard]] std::shared_ptr<Ui::Show> uiShow();
[[nodiscard]] not_null<Ui::RpWindow*> window() const;
rpl::lifetime &lifetime(); rpl::lifetime &lifetime();
@ -148,8 +118,6 @@ private:
Discarded, Discarded,
}; };
[[nodiscard]] not_null<Ui::RpWindow*> window() const;
[[nodiscard]] PanelMode mode() const; [[nodiscard]] PanelMode mode() const;
void paint(QRect clip); void paint(QRect clip);
@ -237,18 +205,11 @@ private:
const not_null<GroupCall*> _call; const not_null<GroupCall*> _call;
not_null<PeerData*> _peer; not_null<PeerData*> _peer;
Ui::GL::Window _window; std::shared_ptr<Window> _window;
const std::unique_ptr<Ui::LayerManager> _layerBg;
rpl::variable<PanelMode> _mode; rpl::variable<PanelMode> _mode;
rpl::variable<bool> _fullScreenOrMaximized = false; rpl::variable<bool> _fullScreenOrMaximized = false;
bool _unpinnedMaximized = false; bool _unpinnedMaximized = false;
bool _rtmpFull = false;
#ifndef Q_OS_MAC
rpl::variable<int> _controlsTop = 0;
const std::unique_ptr<Ui::Platform::SeparateTitleControls> _controls;
#endif // !Q_OS_MAC
const std::unique_ptr<base::PowerSaveBlocker> _powerSaveBlocker;
rpl::lifetime _callLifetime; rpl::lifetime _callLifetime;
@ -305,6 +266,7 @@ private:
rpl::lifetime _hideControlsTimerLifetime; rpl::lifetime _hideControlsTimerLifetime;
rpl::lifetime _peerLifetime; rpl::lifetime _peerLifetime;
rpl::lifetime _lifetime;
}; };

View file

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/group/calls_group_panel.h" #include "calls/group/calls_group_panel.h"
#include "data/data_peer.h" #include "data/data_peer.h"
#include "data/data_group_call.h" #include "data/data_group_call.h"
#include "ui/layers/show.h"
#include "ui/text/text_utilities.h" #include "ui/text/text_utilities.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
@ -49,7 +50,7 @@ void Toasts::setupJoinAsChanged() {
return (state == State::Joined); return (state == State::Joined);
}) | rpl::take(1); }) | rpl::take(1);
}) | rpl::flatten_latest() | rpl::start_with_next([=] { }) | rpl::flatten_latest() | rpl::start_with_next([=] {
_panel->showToast((_call->peer()->isBroadcast() _panel->uiShow()->showToast((_call->peer()->isBroadcast()
? tr::lng_group_call_join_as_changed_channel ? tr::lng_group_call_join_as_changed_channel
: tr::lng_group_call_join_as_changed)( : tr::lng_group_call_join_as_changed)(
tr::now, tr::now,
@ -69,7 +70,7 @@ void Toasts::setupTitleChanged() {
? peer->name() ? peer->name()
: peer->groupCall()->title(); : peer->groupCall()->title();
}) | rpl::start_with_next([=](const QString &title) { }) | rpl::start_with_next([=](const QString &title) {
_panel->showToast((_call->peer()->isBroadcast() _panel->uiShow()->showToast((_call->peer()->isBroadcast()
? tr::lng_group_call_title_changed_channel ? tr::lng_group_call_title_changed_channel
: tr::lng_group_call_title_changed)( : tr::lng_group_call_title_changed)(
tr::now, tr::now,
@ -83,7 +84,8 @@ void Toasts::setupAllowedToSpeak() {
_call->allowedToSpeakNotifications( _call->allowedToSpeakNotifications(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
if (_panel->isActive()) { if (_panel->isActive()) {
_panel->showToast(tr::lng_group_call_can_speak_here(tr::now)); _panel->uiShow()->showToast(
tr::lng_group_call_can_speak_here(tr::now));
} else { } else {
const auto real = _call->lookupReal(); const auto real = _call->lookupReal();
const auto name = (real && !real->title().isEmpty()) const auto name = (real && !real->title().isEmpty())
@ -137,7 +139,7 @@ void Toasts::setupPinnedVideo() {
: tr::lng_group_call_unpinned_screen); : tr::lng_group_call_unpinned_screen);
return key(tr::now, lt_user, peer->shortName()); return key(tr::now, lt_user, peer->shortName());
}(); }();
_panel->showToast(text); _panel->uiShow()->showToast(text);
}, _lifetime); }, _lifetime);
} }
@ -146,7 +148,7 @@ void Toasts::setupRequestedToSpeak() {
) | rpl::combine_previous( ) | rpl::combine_previous(
) | rpl::start_with_next([=](MuteState was, MuteState now) { ) | rpl::start_with_next([=](MuteState was, MuteState now) {
if (was == MuteState::ForceMuted && now == MuteState::RaisedHand) { if (was == MuteState::ForceMuted && now == MuteState::RaisedHand) {
_panel->showToast( _panel->uiShow()->showToast(
tr::lng_group_call_tooltip_raised_hand(tr::now)); tr::lng_group_call_tooltip_raised_hand(tr::now));
} }
}, _lifetime); }, _lifetime);
@ -173,7 +175,7 @@ void Toasts::setupError() {
} }
Unexpected("Error in Calls::Group::Toasts::setupErrorToasts."); Unexpected("Error in Calls::Group::Toasts::setupErrorToasts.");
}(); }();
_panel->showToast({ key(tr::now) }, kErrorDuration); _panel->uiShow()->showToast({ key(tr::now) }, kErrorDuration);
}, _lifetime); }, _lifetime);
} }

@ -1 +1 @@
Subproject commit 720eaf44a529da50f5277fd6874318d9a08b735a Subproject commit 419049fcbe88c68486609232c4db7550833c74ca