mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Toggle fullscreen by mute button in RTMP streams.
This commit is contained in:
parent
25e29d3dd5
commit
fc5ed46b40
11 changed files with 405 additions and 308 deletions
|
@ -270,6 +270,9 @@ callMuteMajorBlobMinRadius: 67px;
|
||||||
callMuteMajorBlobMaxRadius: 77px;
|
callMuteMajorBlobMaxRadius: 77px;
|
||||||
callMuteBlobRadiusForDiameter: 100px;
|
callMuteBlobRadiusForDiameter: 100px;
|
||||||
|
|
||||||
|
callMuteToFullScreen: icon {{ "player/player_fullscreen", groupCallIconFg }};
|
||||||
|
callMuteFromFullScreen: icon {{ "player/player_minimize", groupCallIconFg }};
|
||||||
|
|
||||||
callConnectingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
|
callConnectingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
|
||||||
color: lightButtonFg;
|
color: lightButtonFg;
|
||||||
thickness: 4px;
|
thickness: 4px;
|
||||||
|
@ -489,6 +492,7 @@ callErrorToast: Toast(defaultToast) {
|
||||||
|
|
||||||
groupCallWidth: 380px;
|
groupCallWidth: 380px;
|
||||||
groupCallHeight: 580px;
|
groupCallHeight: 580px;
|
||||||
|
groupCallHeightRtmpMin: 280px;
|
||||||
|
|
||||||
groupCallRipple: RippleAnimation(defaultRippleAnimation) {
|
groupCallRipple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: groupCallMembersBgRipple;
|
color: groupCallMembersBgRipple;
|
||||||
|
|
|
@ -990,9 +990,10 @@ void GroupCall::playConnectingSoundOnce() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GroupCall::showChooseJoinAs() const {
|
bool GroupCall::showChooseJoinAs() const {
|
||||||
return (_possibleJoinAs.size() > 1)
|
return !_rtmp
|
||||||
|| (_possibleJoinAs.size() == 1
|
&& ((_possibleJoinAs.size() > 1)
|
||||||
&& !_possibleJoinAs.front()->isSelf());
|
|| (_possibleJoinAs.size() == 1
|
||||||
|
&& !_possibleJoinAs.front()->isSelf()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GroupCall::scheduleStartSubscribed() const {
|
bool GroupCall::scheduleStartSubscribed() const {
|
||||||
|
@ -1010,6 +1011,14 @@ bool GroupCall::listenersHidden() const {
|
||||||
return _listenersHidden;
|
return _listenersHidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GroupCall::emptyRtmp() const {
|
||||||
|
return _emptyRtmp.current();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<bool> GroupCall::emptyRtmpValue() const {
|
||||||
|
return _emptyRtmp.value();
|
||||||
|
}
|
||||||
|
|
||||||
Data::GroupCall *GroupCall::lookupReal() const {
|
Data::GroupCall *GroupCall::lookupReal() const {
|
||||||
const auto real = _peer->groupCall();
|
const auto real = _peer->groupCall();
|
||||||
return (real && real->id() == _id) ? real : nullptr;
|
return (real && real->id() == _id) ? real : nullptr;
|
||||||
|
@ -2601,7 +2610,8 @@ void GroupCall::requestCurrentTimeStart(
|
||||||
).done([=](const MTPphone_GroupCallStreamChannels &result) {
|
).done([=](const MTPphone_GroupCallStreamChannels &result) {
|
||||||
result.match([&](const MTPDphone_groupCallStreamChannels &data) {
|
result.match([&](const MTPDphone_groupCallStreamChannels &data) {
|
||||||
const auto &list = data.vchannels().v;
|
const auto &list = data.vchannels().v;
|
||||||
if (!list.isEmpty()) {
|
const auto empty = list.isEmpty();
|
||||||
|
if (!empty) {
|
||||||
const auto &first = list.front();
|
const auto &first = list.front();
|
||||||
first.match([&](const MTPDgroupCallStreamChannel &data) {
|
first.match([&](const MTPDgroupCallStreamChannel &data) {
|
||||||
finish(data.vlast_timestamp_ms().v);
|
finish(data.vlast_timestamp_ms().v);
|
||||||
|
@ -2609,6 +2619,7 @@ void GroupCall::requestCurrentTimeStart(
|
||||||
} else {
|
} else {
|
||||||
finish(0);
|
finish(0);
|
||||||
}
|
}
|
||||||
|
_emptyRtmp = empty;
|
||||||
});
|
});
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
finish(0);
|
finish(0);
|
||||||
|
|
|
@ -233,6 +233,8 @@ public:
|
||||||
[[nodiscard]] bool scheduleStartSubscribed() const;
|
[[nodiscard]] bool scheduleStartSubscribed() const;
|
||||||
[[nodiscard]] bool rtmp() const;
|
[[nodiscard]] bool rtmp() const;
|
||||||
[[nodiscard]] bool listenersHidden() const;
|
[[nodiscard]] bool listenersHidden() const;
|
||||||
|
[[nodiscard]] bool emptyRtmp() const;
|
||||||
|
[[nodiscard]] rpl::producer<bool> emptyRtmpValue() const;
|
||||||
|
|
||||||
[[nodiscard]] Data::GroupCall *lookupReal() const;
|
[[nodiscard]] Data::GroupCall *lookupReal() const;
|
||||||
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
|
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
|
||||||
|
@ -593,6 +595,7 @@ private:
|
||||||
rpl::variable<MuteState> _muted = MuteState::Muted;
|
rpl::variable<MuteState> _muted = MuteState::Muted;
|
||||||
rpl::variable<bool> _canManage = false;
|
rpl::variable<bool> _canManage = false;
|
||||||
rpl::variable<bool> _videoIsWorking = false;
|
rpl::variable<bool> _videoIsWorking = false;
|
||||||
|
rpl::variable<bool> _emptyRtmp = false;
|
||||||
bool _initialMuteStateSent = false;
|
bool _initialMuteStateSent = false;
|
||||||
bool _acceptFields = false;
|
bool _acceptFields = false;
|
||||||
|
|
||||||
|
|
|
@ -1191,7 +1191,8 @@ base::unique_qptr<Ui::PopupMenu> Members::Controller::createRowContextMenu(
|
||||||
const auto muted = (muteState == Row::State::Muted)
|
const auto muted = (muteState == Row::State::Muted)
|
||||||
|| (muteState == Row::State::RaisedHand);
|
|| (muteState == Row::State::RaisedHand);
|
||||||
const auto addCover = true;
|
const auto addCover = true;
|
||||||
const auto addVolumeItem = !muted || isMe(participantPeer);
|
const auto addVolumeItem = !_call->rtmp()
|
||||||
|
&& (!muted || isMe(participantPeer));
|
||||||
const auto admin = IsGroupCallAdmin(_peer, participantPeer);
|
const auto admin = IsGroupCallAdmin(_peer, participantPeer);
|
||||||
const auto session = &_peer->session();
|
const auto session = &_peer->session();
|
||||||
const auto getCurrentWindow = [=]() -> Window::SessionController* {
|
const auto getCurrentWindow = [=]() -> Window::SessionController* {
|
||||||
|
@ -1430,7 +1431,8 @@ void Members::Controller::addMuteActionsToContextMenu(
|
||||||
|
|
||||||
auto mutesFromVolume = rpl::never<bool>() | rpl::type_erased();
|
auto mutesFromVolume = rpl::never<bool>() | rpl::type_erased();
|
||||||
|
|
||||||
const auto addVolumeItem = !muted || isMe(participantPeer);
|
const auto addVolumeItem = !_call->rtmp()
|
||||||
|
&& (!muted || isMe(participantPeer));
|
||||||
if (addVolumeItem) {
|
if (addVolumeItem) {
|
||||||
auto otherParticipantStateValue
|
auto otherParticipantStateValue
|
||||||
= _call->otherParticipantStateValue(
|
= _call->otherParticipantStateValue(
|
||||||
|
@ -1492,6 +1494,7 @@ void Members::Controller::addMuteActionsToContextMenu(
|
||||||
|
|
||||||
const auto muteAction = [&]() -> QAction* {
|
const auto muteAction = [&]() -> QAction* {
|
||||||
if (muteState == Row::State::Invited
|
if (muteState == Row::State::Invited
|
||||||
|
|| _call->rtmp()
|
||||||
|| isMe(participantPeer)
|
|| isMe(participantPeer)
|
||||||
|| (muteState == Row::State::Inactive
|
|| (muteState == Row::State::Inactive
|
||||||
&& participantIsCallAdmin
|
&& participantIsCallAdmin
|
||||||
|
|
|
@ -114,6 +114,9 @@ Panel::Panel(not_null<GroupCall*> call)
|
||||||
: _call->scheduleStartSubscribed()
|
: _call->scheduleStartSubscribed()
|
||||||
? Ui::CallMuteButtonType::ScheduledNotify
|
? Ui::CallMuteButtonType::ScheduledNotify
|
||||||
: Ui::CallMuteButtonType::ScheduledSilent),
|
: Ui::CallMuteButtonType::ScheduledSilent),
|
||||||
|
.expandType = ((_call->scheduleDate() || !_call->rtmp())
|
||||||
|
? Ui::CallMuteButtonExpandType::None
|
||||||
|
: Ui::CallMuteButtonExpandType::Normal),
|
||||||
}))
|
}))
|
||||||
, _hangup(widget(), st::groupCallHangup)
|
, _hangup(widget(), st::groupCallHangup)
|
||||||
, _stickedTooltipsShown(Core::App().settings().hiddenGroupCallTooltips()
|
, _stickedTooltipsShown(Core::App().settings().hiddenGroupCallTooltips()
|
||||||
|
@ -257,22 +260,34 @@ void Panel::initWindow() {
|
||||||
return base::EventFilterResult::Cancel;
|
return base::EventFilterResult::Cancel;
|
||||||
} else if (e->type() == QEvent::KeyPress
|
} else if (e->type() == QEvent::KeyPress
|
||||||
|| e->type() == QEvent::KeyRelease) {
|
|| e->type() == QEvent::KeyRelease) {
|
||||||
if (static_cast<QKeyEvent*>(e.get())->key() == Qt::Key_Space) {
|
const auto key = static_cast<QKeyEvent*>(e.get())->key();
|
||||||
|
if (key == Qt::Key_Space) {
|
||||||
_call->pushToTalk(
|
_call->pushToTalk(
|
||||||
e->type() == QEvent::KeyPress,
|
e->type() == QEvent::KeyPress,
|
||||||
kSpacePushToTalkDelay);
|
kSpacePushToTalkDelay);
|
||||||
|
} else if (key == Qt::Key_Escape && _fullScreen.current()) {
|
||||||
|
toggleFullScreen(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return base::EventFilterResult::Continue;
|
return base::EventFilterResult::Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
window()->windowHandle(),
|
||||||
|
&QWindow::windowStateChanged,
|
||||||
|
[=](Qt::WindowState state) {
|
||||||
|
_fullScreen = (state == Qt::WindowFullScreen);
|
||||||
|
});
|
||||||
|
|
||||||
window()->setBodyTitleArea([=](QPoint widgetPoint) {
|
window()->setBodyTitleArea([=](QPoint widgetPoint) {
|
||||||
using Flag = Ui::WindowTitleHitTestFlag;
|
using Flag = Ui::WindowTitleHitTestFlag;
|
||||||
const auto titleRect = QRect(
|
const auto titleRect = QRect(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
widget()->width(),
|
widget()->width(),
|
||||||
st::groupCallMembersTop);
|
(mode() == PanelMode::Wide
|
||||||
|
? st::groupCallWideVideoTop
|
||||||
|
: st::groupCallMembersTop));
|
||||||
const auto moveable = (titleRect.contains(widgetPoint)
|
const auto moveable = (titleRect.contains(widgetPoint)
|
||||||
&& (!_menuToggle || !_menuToggle->geometry().contains(widgetPoint))
|
&& (!_menuToggle || !_menuToggle->geometry().contains(widgetPoint))
|
||||||
&& (!_menu || !_menu->geometry().contains(widgetPoint))
|
&& (!_menu || !_menu->geometry().contains(widgetPoint))
|
||||||
|
@ -365,7 +380,11 @@ void Panel::initControls() {
|
||||||
!real->scheduleStartSubscribed());
|
!real->scheduleStartSubscribed());
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
} else if (_call->rtmp()) {
|
||||||
|
toggleFullScreen(!_fullScreen.current());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto oldState = _call->muted();
|
const auto oldState = _call->muted();
|
||||||
const auto newState = (oldState == MuteState::ForceMuted)
|
const auto newState = (oldState == MuteState::ForceMuted)
|
||||||
? MuteState::RaisedHand
|
? MuteState::RaisedHand
|
||||||
|
@ -450,6 +469,14 @@ void Panel::initControls() {
|
||||||
refreshControlsBackground();
|
refreshControlsBackground();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Panel::toggleFullScreen(bool fullscreen) {
|
||||||
|
if (fullscreen) {
|
||||||
|
window()->showFullScreen();
|
||||||
|
} else {
|
||||||
|
window()->showNormal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Panel::refreshLeftButton() {
|
void Panel::refreshLeftButton() {
|
||||||
const auto share = _call->scheduleDate()
|
const auto share = _call->scheduleDate()
|
||||||
&& _peer->isBroadcast()
|
&& _peer->isBroadcast()
|
||||||
|
@ -467,6 +494,7 @@ void Panel::refreshLeftButton() {
|
||||||
_settings->setClickedCallback([=] {
|
_settings->setClickedCallback([=] {
|
||||||
showBox(Box(SettingsBox, _call));
|
showBox(Box(SettingsBox, _call));
|
||||||
});
|
});
|
||||||
|
trackControls(_trackControls, true);
|
||||||
}
|
}
|
||||||
const auto raw = _callShare ? _callShare.data() : _settings.data();
|
const auto raw = _callShare ? _callShare.data() : _settings.data();
|
||||||
raw->show();
|
raw->show();
|
||||||
|
@ -615,7 +643,8 @@ void Panel::setupRealMuteButtonState(not_null<Data::GroupCall*> real) {
|
||||||
real->scheduleDateValue(),
|
real->scheduleDateValue(),
|
||||||
real->scheduleStartSubscribedValue(),
|
real->scheduleStartSubscribedValue(),
|
||||||
_call->canManageValue(),
|
_call->canManageValue(),
|
||||||
_mode.value()
|
_mode.value(),
|
||||||
|
_fullScreen.value()
|
||||||
) | rpl::distinct_until_changed(
|
) | rpl::distinct_until_changed(
|
||||||
) | rpl::filter(
|
) | rpl::filter(
|
||||||
_2 != GroupCall::InstanceState::TransitionToRtc
|
_2 != GroupCall::InstanceState::TransitionToRtc
|
||||||
|
@ -625,9 +654,11 @@ void Panel::setupRealMuteButtonState(not_null<Data::GroupCall*> real) {
|
||||||
TimeId scheduleDate,
|
TimeId scheduleDate,
|
||||||
bool scheduleStartSubscribed,
|
bool scheduleStartSubscribed,
|
||||||
bool canManage,
|
bool canManage,
|
||||||
PanelMode mode) {
|
PanelMode mode,
|
||||||
|
bool fullScreen) {
|
||||||
const auto wide = (mode == PanelMode::Wide);
|
const auto wide = (mode == PanelMode::Wide);
|
||||||
using Type = Ui::CallMuteButtonType;
|
using Type = Ui::CallMuteButtonType;
|
||||||
|
using ExpandType = Ui::CallMuteButtonExpandType;
|
||||||
_mute->setState(Ui::CallMuteButtonState{
|
_mute->setState(Ui::CallMuteButtonState{
|
||||||
.text = (wide
|
.text = (wide
|
||||||
? QString()
|
? QString()
|
||||||
|
@ -664,6 +695,11 @@ void Panel::setupRealMuteButtonState(not_null<Data::GroupCall*> real) {
|
||||||
: mute == MuteState::Muted
|
: mute == MuteState::Muted
|
||||||
? Type::Muted
|
? Type::Muted
|
||||||
: Type::Active),
|
: Type::Active),
|
||||||
|
.expandType = ((scheduleDate || !_call->rtmp())
|
||||||
|
? ExpandType::None
|
||||||
|
: fullScreen
|
||||||
|
? ExpandType::Expanded
|
||||||
|
: ExpandType::Normal),
|
||||||
});
|
});
|
||||||
}, _callLifetime);
|
}, _callLifetime);
|
||||||
}
|
}
|
||||||
|
@ -860,8 +896,10 @@ void Panel::minimizeVideo() {
|
||||||
}
|
}
|
||||||
const auto available = window()->screen()->availableGeometry();
|
const auto available = window()->screen()->availableGeometry();
|
||||||
const auto width = st::groupCallWidth;
|
const auto width = st::groupCallWidth;
|
||||||
const auto height = st::groupCallHeight;
|
const auto height = _call->rtmp()
|
||||||
auto geometry = QRect(
|
? st::groupCallHeightRtmpMin
|
||||||
|
: st::groupCallHeight;
|
||||||
|
const auto geometry = QRect(
|
||||||
window()->x() + (window()->width() - width) / 2,
|
window()->x() + (window()->width() - width) / 2,
|
||||||
window()->y() + (window()->height() - height) / 2,
|
window()->y() + (window()->height() - height) / 2,
|
||||||
width,
|
width,
|
||||||
|
@ -1277,13 +1315,14 @@ void Panel::showMainMenu() {
|
||||||
|
|
||||||
if (wide) {
|
if (wide) {
|
||||||
_wideMenu->installEventFilter(_menu);
|
_wideMenu->installEventFilter(_menu);
|
||||||
|
trackControl(_menu, _trackControlsMenuLifetime);
|
||||||
|
|
||||||
const auto x = st::groupCallWideMenuPosition.x();
|
const auto x = st::groupCallWideMenuPosition.x();
|
||||||
const auto y = st::groupCallWideMenuPosition.y();
|
const auto y = st::groupCallWideMenuPosition.y();
|
||||||
_menu->moveToLeft(
|
_menu->moveToLeft(
|
||||||
_wideMenu->x() + x,
|
_wideMenu->x() + x,
|
||||||
_wideMenu->y() - _menu->height() + y);
|
_wideMenu->y() - _menu->height() + y);
|
||||||
_menu->showAnimated(Ui::PanelAnimation::Origin::BottomLeft);
|
_menu->showAnimated(Ui::PanelAnimation::Origin::BottomLeft);
|
||||||
trackControl(_menu, _trackControlsMenuLifetime);
|
|
||||||
} else {
|
} else {
|
||||||
_menuToggle->installEventFilter(_menu);
|
_menuToggle->installEventFilter(_menu);
|
||||||
const auto x = st::groupCallMenuPosition.x();
|
const auto x = st::groupCallMenuPosition.x();
|
||||||
|
@ -1404,7 +1443,10 @@ rpl::lifetime &Panel::lifetime() {
|
||||||
|
|
||||||
void Panel::initGeometry() {
|
void Panel::initGeometry() {
|
||||||
const auto center = Core::App().getPointForCallPanelCenter();
|
const auto center = Core::App().getPointForCallPanelCenter();
|
||||||
const auto rect = QRect(0, 0, st::groupCallWidth, st::groupCallHeight);
|
const auto height = (_call->rtmp() && !_call->canManage())
|
||||||
|
? st::groupCallHeightRtmpMin
|
||||||
|
: st::groupCallHeight;
|
||||||
|
const auto rect = QRect(0, 0, st::groupCallWidth, height);
|
||||||
window()->setGeometry(rect.translated(center - rect.center()));
|
window()->setGeometry(rect.translated(center - rect.center()));
|
||||||
window()->setMinimumSize(rect.size());
|
window()->setMinimumSize(rect.size());
|
||||||
window()->show();
|
window()->show();
|
||||||
|
@ -1854,15 +1896,14 @@ void Panel::updateTooltipGeometry() {
|
||||||
_niceTooltip->pointAt(geometry, RectPart::Top, countPosition);
|
_niceTooltip->pointAt(geometry, RectPart::Top, countPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Panel::trackControls(bool track) {
|
void Panel::trackControls(bool track, bool force) {
|
||||||
if (_trackControls == track) {
|
if (!force && _trackControls == track) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_trackControls = track;
|
_trackControls = track;
|
||||||
|
_trackControlsOverStateLifetime.destroy();
|
||||||
|
_trackControlsMenuLifetime.destroy();
|
||||||
if (!track) {
|
if (!track) {
|
||||||
_trackControlsLifetime.destroy();
|
|
||||||
_trackControlsOverStateLifetime.destroy();
|
|
||||||
_trackControlsMenuLifetime.destroy();
|
|
||||||
toggleWideControls(true);
|
toggleWideControls(true);
|
||||||
if (_wideControlsAnimation.animating()) {
|
if (_wideControlsAnimation.animating()) {
|
||||||
_wideControlsAnimation.stop();
|
_wideControlsAnimation.stop();
|
||||||
|
@ -1932,12 +1973,13 @@ void Panel::updateButtonsGeometry() {
|
||||||
Assert(_settings != nullptr);
|
Assert(_settings != nullptr);
|
||||||
Assert(_callShare == nullptr);
|
Assert(_callShare == nullptr);
|
||||||
|
|
||||||
|
const auto rtmp = _call->rtmp();
|
||||||
const auto shown = _wideControlsAnimation.value(
|
const auto shown = _wideControlsAnimation.value(
|
||||||
_wideControlsShown ? 1. : 0.);
|
_wideControlsShown ? 1. : 0.);
|
||||||
const auto hidden = (shown == 0.);
|
const auto hidden = (shown == 0.);
|
||||||
|
|
||||||
if (_viewport) {
|
if (_viewport) {
|
||||||
_viewport->setControlsShown(_call->rtmp() ? 0. : shown);
|
_viewport->setControlsShown(rtmp ? 0. : shown);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto buttonsTop = widget()->height() - anim::interpolate(
|
const auto buttonsTop = widget()->height() - anim::interpolate(
|
||||||
|
@ -1947,10 +1989,10 @@ void Panel::updateButtonsGeometry() {
|
||||||
const auto addSkip = st::callMuteButtonSmall.active.outerRadius;
|
const auto addSkip = st::callMuteButtonSmall.active.outerRadius;
|
||||||
const auto muteSize = _mute->innerSize().width() + 2 * addSkip;
|
const auto muteSize = _mute->innerSize().width() + 2 * addSkip;
|
||||||
const auto skip = st::groupCallButtonSkipSmall;
|
const auto skip = st::groupCallButtonSkipSmall;
|
||||||
const auto fullWidth = (_video->width() + skip)
|
const auto fullWidth = (rtmp ? 0 : (_video->width() + skip))
|
||||||
+ (_screenShare->width() + skip)
|
+ (rtmp ? 0 : (_screenShare->width() + skip))
|
||||||
+ (muteSize + skip)
|
+ (muteSize + skip)
|
||||||
+ (_settings ->width() + skip)
|
+ (_settings->width() + skip)
|
||||||
+ _hangup->width();
|
+ _hangup->width();
|
||||||
const auto membersSkip = st::groupCallNarrowSkip;
|
const auto membersSkip = st::groupCallNarrowSkip;
|
||||||
const auto membersWidth = _call->rtmp()
|
const auto membersWidth = _call->rtmp()
|
||||||
|
@ -1960,12 +2002,20 @@ void Panel::updateButtonsGeometry() {
|
||||||
- membersWidth
|
- membersWidth
|
||||||
- membersSkip
|
- membersSkip
|
||||||
- fullWidth) / 2;
|
- fullWidth) / 2;
|
||||||
toggle(_screenShare, !hidden);
|
toggle(_screenShare, !hidden && !rtmp);
|
||||||
_screenShare->moveToLeft(left, buttonsTop);
|
if (!rtmp) {
|
||||||
left += _screenShare->width() + skip;
|
_screenShare->moveToLeft(left, buttonsTop);
|
||||||
toggle(_video, !hidden);
|
left += _screenShare->width() + skip;
|
||||||
_video->moveToLeft(left, buttonsTop);
|
}
|
||||||
left += _video->width() + skip;
|
toggle(_video, !hidden && !rtmp);
|
||||||
|
if (!rtmp) {
|
||||||
|
_video->moveToLeft(left, buttonsTop);
|
||||||
|
left += _video->width() + skip;
|
||||||
|
} else {
|
||||||
|
_wideMenu->moveToLeft(left, buttonsTop);
|
||||||
|
_settings->moveToLeft(left, buttonsTop);
|
||||||
|
left += _settings->width() + skip;
|
||||||
|
}
|
||||||
toggle(_mute, !hidden);
|
toggle(_mute, !hidden);
|
||||||
_mute->moveInner({ left + addSkip, buttonsTop + addSkip });
|
_mute->moveInner({ left + addSkip, buttonsTop + addSkip });
|
||||||
left += muteSize + skip;
|
left += muteSize + skip;
|
||||||
|
@ -1973,9 +2023,11 @@ void Panel::updateButtonsGeometry() {
|
||||||
|| _call->showChooseJoinAs();
|
|| _call->showChooseJoinAs();
|
||||||
toggle(_settings, !hidden && !wideMenuShown);
|
toggle(_settings, !hidden && !wideMenuShown);
|
||||||
toggle(_wideMenu, !hidden && wideMenuShown);
|
toggle(_wideMenu, !hidden && wideMenuShown);
|
||||||
_wideMenu->moveToLeft(left, buttonsTop);
|
if (!rtmp) {
|
||||||
_settings->moveToLeft(left, buttonsTop);
|
_wideMenu->moveToLeft(left, buttonsTop);
|
||||||
left += _settings->width() + skip;
|
_settings->moveToLeft(left, buttonsTop);
|
||||||
|
left += _settings->width() + skip;
|
||||||
|
}
|
||||||
toggle(_hangup, !hidden);
|
toggle(_hangup, !hidden);
|
||||||
_hangup->moveToLeft(left, buttonsTop);
|
_hangup->moveToLeft(left, buttonsTop);
|
||||||
left += _hangup->width();
|
left += _hangup->width();
|
||||||
|
|
|
@ -130,7 +130,8 @@ private:
|
||||||
|
|
||||||
bool handleClose();
|
bool handleClose();
|
||||||
void startScheduledNow();
|
void startScheduledNow();
|
||||||
void trackControls(bool track);
|
void toggleFullScreen(bool fullscreen);
|
||||||
|
void trackControls(bool track, bool force = false);
|
||||||
void raiseControls();
|
void raiseControls();
|
||||||
void enlargeVideo();
|
void enlargeVideo();
|
||||||
void minimizeVideo();
|
void minimizeVideo();
|
||||||
|
@ -197,6 +198,7 @@ private:
|
||||||
Ui::GL::Window _window;
|
Ui::GL::Window _window;
|
||||||
const std::unique_ptr<Ui::LayerManager> _layerBg;
|
const std::unique_ptr<Ui::LayerManager> _layerBg;
|
||||||
rpl::variable<PanelMode> _mode;
|
rpl::variable<PanelMode> _mode;
|
||||||
|
rpl::variable<bool> _fullScreen = false;
|
||||||
|
|
||||||
#ifndef Q_OS_MAC
|
#ifndef Q_OS_MAC
|
||||||
std::unique_ptr<Ui::Platform::SeparateTitleControls> _controls;
|
std::unique_ptr<Ui::Platform::SeparateTitleControls> _controls;
|
||||||
|
@ -215,7 +217,6 @@ private:
|
||||||
object_ptr<Ui::AbstractButton> _joinAsToggle = { nullptr };
|
object_ptr<Ui::AbstractButton> _joinAsToggle = { nullptr };
|
||||||
object_ptr<Members> _members = { nullptr };
|
object_ptr<Members> _members = { nullptr };
|
||||||
std::unique_ptr<Viewport> _viewport;
|
std::unique_ptr<Viewport> _viewport;
|
||||||
rpl::lifetime _trackControlsLifetime;
|
|
||||||
rpl::lifetime _trackControlsOverStateLifetime;
|
rpl::lifetime _trackControlsOverStateLifetime;
|
||||||
rpl::lifetime _trackControlsMenuLifetime;
|
rpl::lifetime _trackControlsMenuLifetime;
|
||||||
object_ptr<Ui::FlatLabel> _startsIn = { nullptr };
|
object_ptr<Ui::FlatLabel> _startsIn = { nullptr };
|
||||||
|
|
|
@ -235,6 +235,7 @@ void SettingsBox(
|
||||||
const auto peer = call->peer();
|
const auto peer = call->peer();
|
||||||
const auto state = box->lifetime().make_state<State>();
|
const auto state = box->lifetime().make_state<State>();
|
||||||
const auto real = peer->groupCall();
|
const auto real = peer->groupCall();
|
||||||
|
const auto rtmp = call->rtmp();
|
||||||
const auto id = call->id();
|
const auto id = call->id();
|
||||||
const auto goodReal = (real && real->id() == id);
|
const auto goodReal = (real && real->id() == id);
|
||||||
|
|
||||||
|
@ -274,280 +275,280 @@ void SettingsBox(
|
||||||
}), &st::groupCallCheckbox, &st::groupCallRadio));
|
}), &st::groupCallCheckbox, &st::groupCallRadio));
|
||||||
});
|
});
|
||||||
|
|
||||||
AddButtonWithLabel(
|
if (!rtmp) {
|
||||||
layout,
|
AddButtonWithLabel(
|
||||||
tr::lng_group_call_microphone(),
|
|
||||||
rpl::single(
|
|
||||||
CurrentAudioInputName()
|
|
||||||
) | rpl::then(
|
|
||||||
state->inputNameStream.events()
|
|
||||||
),
|
|
||||||
st::groupCallSettingsButton
|
|
||||||
)->addClickHandler([=] {
|
|
||||||
box->getDelegate()->show(ChooseAudioInputBox(crl::guard(box, [=](
|
|
||||||
const QString &id,
|
|
||||||
const QString &name) {
|
|
||||||
state->inputNameStream.fire_copy(name);
|
|
||||||
if (state->micTester) {
|
|
||||||
state->micTester->setDeviceId(id);
|
|
||||||
}
|
|
||||||
}), &st::groupCallCheckbox, &st::groupCallRadio));
|
|
||||||
});
|
|
||||||
|
|
||||||
state->micTestLevel = box->addRow(
|
|
||||||
object_ptr<Ui::LevelMeter>(
|
|
||||||
box.get(),
|
|
||||||
st::groupCallLevelMeter),
|
|
||||||
st::settingsLevelMeterPadding);
|
|
||||||
state->micTestLevel->resize(QSize(0, st::defaultLevelMeter.height));
|
|
||||||
|
|
||||||
state->levelUpdateTimer.setCallback([=] {
|
|
||||||
const auto was = state->micLevel;
|
|
||||||
state->micLevel = state->micTester->getAndResetLevel();
|
|
||||||
state->micLevelAnimation.start([=] {
|
|
||||||
state->micTestLevel->setValue(
|
|
||||||
state->micLevelAnimation.value(state->micLevel));
|
|
||||||
}, was, state->micLevel, kMicTestAnimationDuration);
|
|
||||||
});
|
|
||||||
|
|
||||||
AddSkip(layout);
|
|
||||||
//AddDivider(layout);
|
|
||||||
//AddSkip(layout);
|
|
||||||
|
|
||||||
AddButton(
|
|
||||||
layout,
|
|
||||||
tr::lng_group_call_noise_suppression(),
|
|
||||||
st::groupCallSettingsButton
|
|
||||||
)->toggleOn(rpl::single(
|
|
||||||
settings.groupCallNoiseSuppression()
|
|
||||||
))->toggledChanges(
|
|
||||||
) | rpl::start_with_next([=](bool enabled) {
|
|
||||||
Core::App().settings().setGroupCallNoiseSuppression(enabled);
|
|
||||||
call->setNoiseSuppression(enabled);
|
|
||||||
Core::App().saveSettingsDelayed();
|
|
||||||
}, layout->lifetime());
|
|
||||||
|
|
||||||
|
|
||||||
using GlobalShortcut = base::GlobalShortcut;
|
|
||||||
struct PushToTalkState {
|
|
||||||
rpl::variable<QString> recordText = tr::lng_group_call_ptt_shortcut();
|
|
||||||
rpl::variable<QString> shortcutText;
|
|
||||||
rpl::event_stream<bool> pushToTalkToggles;
|
|
||||||
std::shared_ptr<base::GlobalShortcutManager> manager;
|
|
||||||
GlobalShortcut shortcut;
|
|
||||||
crl::time delay = 0;
|
|
||||||
bool recording = false;
|
|
||||||
};
|
|
||||||
if (base::GlobalShortcutsAvailable()) {
|
|
||||||
const auto state = box->lifetime().make_state<PushToTalkState>();
|
|
||||||
if (!base::GlobalShortcutsAllowed()) {
|
|
||||||
Core::App().settings().setGroupCallPushToTalk(false);
|
|
||||||
}
|
|
||||||
const auto tryFillFromManager = [=] {
|
|
||||||
state->shortcut = state->manager
|
|
||||||
? state->manager->shortcutFromSerialized(
|
|
||||||
Core::App().settings().groupCallPushToTalkShortcut())
|
|
||||||
: nullptr;
|
|
||||||
state->shortcutText = state->shortcut
|
|
||||||
? state->shortcut->toDisplayString()
|
|
||||||
: QString();
|
|
||||||
};
|
|
||||||
state->manager = settings.groupCallPushToTalk()
|
|
||||||
? call->ensureGlobalShortcutManager()
|
|
||||||
: nullptr;
|
|
||||||
tryFillFromManager();
|
|
||||||
|
|
||||||
state->delay = settings.groupCallPushToTalkDelay();
|
|
||||||
const auto pushToTalk = AddButton(
|
|
||||||
layout,
|
layout,
|
||||||
tr::lng_group_call_push_to_talk(),
|
tr::lng_group_call_microphone(),
|
||||||
|
rpl::single(
|
||||||
|
CurrentAudioInputName()
|
||||||
|
) | rpl::then(
|
||||||
|
state->inputNameStream.events()
|
||||||
|
),
|
||||||
st::groupCallSettingsButton
|
st::groupCallSettingsButton
|
||||||
)->toggleOn(rpl::single(
|
)->addClickHandler([=] {
|
||||||
settings.groupCallPushToTalk()
|
box->getDelegate()->show(ChooseAudioInputBox(crl::guard(box, [=](
|
||||||
) | rpl::then(state->pushToTalkToggles.events()));
|
const QString &id,
|
||||||
const auto pushToTalkWrap = layout->add(
|
const QString &name) {
|
||||||
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
state->inputNameStream.fire_copy(name);
|
||||||
layout,
|
if (state->micTester) {
|
||||||
object_ptr<Ui::VerticalLayout>(layout)));
|
state->micTester->setDeviceId(id);
|
||||||
const auto pushToTalkInner = pushToTalkWrap->entity();
|
|
||||||
const auto recording = AddButton(
|
|
||||||
pushToTalkInner,
|
|
||||||
state->recordText.value(),
|
|
||||||
st::groupCallSettingsButton);
|
|
||||||
CreateRightLabel(
|
|
||||||
recording,
|
|
||||||
state->shortcutText.value(),
|
|
||||||
st::groupCallSettingsButton,
|
|
||||||
state->recordText.value());
|
|
||||||
|
|
||||||
const auto applyAndSave = [=] {
|
|
||||||
call->applyGlobalShortcutChanges();
|
|
||||||
Core::App().saveSettingsDelayed();
|
|
||||||
};
|
|
||||||
const auto showPrivacyRequest = [=] {
|
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
if (!Platform::IsMac10_14OrGreater()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto requestInputMonitoring = Platform::IsMac10_15OrGreater();
|
|
||||||
box->getDelegate()->show(Box([=](not_null<Ui::GenericBox*> box) {
|
|
||||||
box->addRow(
|
|
||||||
object_ptr<Ui::FlatLabel>(
|
|
||||||
box.get(),
|
|
||||||
rpl::combine(
|
|
||||||
tr::lng_group_call_mac_access(),
|
|
||||||
(requestInputMonitoring
|
|
||||||
? tr::lng_group_call_mac_input()
|
|
||||||
: tr::lng_group_call_mac_accessibility())
|
|
||||||
) | rpl::map([](QString a, QString b) {
|
|
||||||
auto result = Ui::Text::RichLangValue(a);
|
|
||||||
result.append("\n\n").append(Ui::Text::RichLangValue(b));
|
|
||||||
return result;
|
|
||||||
}),
|
|
||||||
st::groupCallBoxLabel),
|
|
||||||
style::margins(
|
|
||||||
st::boxRowPadding.left(),
|
|
||||||
st::boxPadding.top(),
|
|
||||||
st::boxRowPadding.right(),
|
|
||||||
st::boxPadding.bottom()));
|
|
||||||
box->addButton(tr::lng_group_call_mac_settings(), [=] {
|
|
||||||
if (requestInputMonitoring) {
|
|
||||||
Platform::OpenInputMonitoringPrivacySettings();
|
|
||||||
} else {
|
|
||||||
Platform::OpenAccessibilityPrivacySettings();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
|
||||||
|
|
||||||
if (!requestInputMonitoring) {
|
|
||||||
// Accessibility is enabled without app restart, so short-poll it.
|
|
||||||
base::timer_each(
|
|
||||||
kCheckAccessibilityInterval
|
|
||||||
) | rpl::filter([] {
|
|
||||||
return base::GlobalShortcutsAllowed();
|
|
||||||
}) | rpl::start_with_next([=] {
|
|
||||||
box->closeBox();
|
|
||||||
}, box->lifetime());
|
|
||||||
}
|
}
|
||||||
}));
|
}), &st::groupCallCheckbox, &st::groupCallRadio));
|
||||||
#endif // Q_OS_MAC
|
|
||||||
};
|
|
||||||
const auto ensureManager = [=] {
|
|
||||||
if (state->manager) {
|
|
||||||
return true;
|
|
||||||
} else if (base::GlobalShortcutsAllowed()) {
|
|
||||||
state->manager = call->ensureGlobalShortcutManager();
|
|
||||||
tryFillFromManager();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
showPrivacyRequest();
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
const auto stopRecording = [=] {
|
|
||||||
state->recording = false;
|
|
||||||
state->recordText = tr::lng_group_call_ptt_shortcut();
|
|
||||||
state->shortcutText = state->shortcut
|
|
||||||
? state->shortcut->toDisplayString()
|
|
||||||
: QString();
|
|
||||||
recording->setColorOverride(std::nullopt);
|
|
||||||
if (state->manager) {
|
|
||||||
state->manager->stopRecording();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const auto startRecording = [=] {
|
|
||||||
if (!ensureManager()) {
|
|
||||||
state->pushToTalkToggles.fire(false);
|
|
||||||
pushToTalkWrap->hide(anim::type::instant);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state->recording = true;
|
|
||||||
state->recordText = tr::lng_group_call_ptt_recording();
|
|
||||||
recording->setColorOverride(
|
|
||||||
st::groupCallSettingsAttentionButton.textFg->c);
|
|
||||||
auto progress = crl::guard(box, [=](GlobalShortcut shortcut) {
|
|
||||||
state->shortcutText = shortcut->toDisplayString();
|
|
||||||
});
|
|
||||||
auto done = crl::guard(box, [=](GlobalShortcut shortcut) {
|
|
||||||
state->shortcut = shortcut;
|
|
||||||
Core::App().settings().setGroupCallPushToTalkShortcut(shortcut
|
|
||||||
? shortcut->serialize()
|
|
||||||
: QByteArray());
|
|
||||||
applyAndSave();
|
|
||||||
stopRecording();
|
|
||||||
});
|
|
||||||
state->manager->startRecording(std::move(progress), std::move(done));
|
|
||||||
};
|
|
||||||
recording->addClickHandler([=] {
|
|
||||||
if (state->recording) {
|
|
||||||
stopRecording();
|
|
||||||
} else {
|
|
||||||
startRecording();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const auto label = pushToTalkInner->add(
|
state->micTestLevel = box->addRow(
|
||||||
object_ptr<Ui::LabelSimple>(
|
object_ptr<Ui::LevelMeter>(
|
||||||
|
box.get(),
|
||||||
|
st::groupCallLevelMeter),
|
||||||
|
st::settingsLevelMeterPadding);
|
||||||
|
state->micTestLevel->resize(QSize(0, st::defaultLevelMeter.height));
|
||||||
|
|
||||||
|
state->levelUpdateTimer.setCallback([=] {
|
||||||
|
const auto was = state->micLevel;
|
||||||
|
state->micLevel = state->micTester->getAndResetLevel();
|
||||||
|
state->micLevelAnimation.start([=] {
|
||||||
|
state->micTestLevel->setValue(
|
||||||
|
state->micLevelAnimation.value(state->micLevel));
|
||||||
|
}, was, state->micLevel, kMicTestAnimationDuration);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddSkip(layout);
|
||||||
|
//AddDivider(layout);
|
||||||
|
//AddSkip(layout);
|
||||||
|
|
||||||
|
AddButton(
|
||||||
|
layout,
|
||||||
|
tr::lng_group_call_noise_suppression(),
|
||||||
|
st::groupCallSettingsButton
|
||||||
|
)->toggleOn(rpl::single(
|
||||||
|
settings.groupCallNoiseSuppression()
|
||||||
|
))->toggledChanges(
|
||||||
|
) | rpl::start_with_next([=](bool enabled) {
|
||||||
|
Core::App().settings().setGroupCallNoiseSuppression(enabled);
|
||||||
|
call->setNoiseSuppression(enabled);
|
||||||
|
Core::App().saveSettingsDelayed();
|
||||||
|
}, layout->lifetime());
|
||||||
|
|
||||||
|
using GlobalShortcut = base::GlobalShortcut;
|
||||||
|
struct PushToTalkState {
|
||||||
|
rpl::variable<QString> recordText = tr::lng_group_call_ptt_shortcut();
|
||||||
|
rpl::variable<QString> shortcutText;
|
||||||
|
rpl::event_stream<bool> pushToTalkToggles;
|
||||||
|
std::shared_ptr<base::GlobalShortcutManager> manager;
|
||||||
|
GlobalShortcut shortcut;
|
||||||
|
crl::time delay = 0;
|
||||||
|
bool recording = false;
|
||||||
|
};
|
||||||
|
if (base::GlobalShortcutsAvailable()) {
|
||||||
|
const auto state = box->lifetime().make_state<PushToTalkState>();
|
||||||
|
if (!base::GlobalShortcutsAllowed()) {
|
||||||
|
Core::App().settings().setGroupCallPushToTalk(false);
|
||||||
|
}
|
||||||
|
const auto tryFillFromManager = [=] {
|
||||||
|
state->shortcut = state->manager
|
||||||
|
? state->manager->shortcutFromSerialized(
|
||||||
|
Core::App().settings().groupCallPushToTalkShortcut())
|
||||||
|
: nullptr;
|
||||||
|
state->shortcutText = state->shortcut
|
||||||
|
? state->shortcut->toDisplayString()
|
||||||
|
: QString();
|
||||||
|
};
|
||||||
|
state->manager = settings.groupCallPushToTalk()
|
||||||
|
? call->ensureGlobalShortcutManager()
|
||||||
|
: nullptr;
|
||||||
|
tryFillFromManager();
|
||||||
|
|
||||||
|
state->delay = settings.groupCallPushToTalkDelay();
|
||||||
|
const auto pushToTalk = AddButton(
|
||||||
|
layout,
|
||||||
|
tr::lng_group_call_push_to_talk(),
|
||||||
|
st::groupCallSettingsButton
|
||||||
|
)->toggleOn(rpl::single(
|
||||||
|
settings.groupCallPushToTalk()
|
||||||
|
) | rpl::then(state->pushToTalkToggles.events()));
|
||||||
|
const auto pushToTalkWrap = layout->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
|
||||||
|
layout,
|
||||||
|
object_ptr<Ui::VerticalLayout>(layout)));
|
||||||
|
const auto pushToTalkInner = pushToTalkWrap->entity();
|
||||||
|
const auto recording = AddButton(
|
||||||
pushToTalkInner,
|
pushToTalkInner,
|
||||||
st::groupCallDelayLabel),
|
state->recordText.value(),
|
||||||
st::groupCallDelayLabelMargin);
|
st::groupCallSettingsButton);
|
||||||
const auto value = std::clamp(
|
CreateRightLabel(
|
||||||
state->delay,
|
recording,
|
||||||
crl::time(0),
|
state->shortcutText.value(),
|
||||||
DelayByIndex(kDelaysCount - 1));
|
st::groupCallSettingsButton,
|
||||||
const auto callback = [=](crl::time delay) {
|
state->recordText.value());
|
||||||
state->delay = delay;
|
|
||||||
label->setText(tr::lng_group_call_ptt_delay(
|
const auto applyAndSave = [=] {
|
||||||
tr::now,
|
call->applyGlobalShortcutChanges();
|
||||||
lt_delay,
|
Core::App().saveSettingsDelayed();
|
||||||
FormatDelay(delay)));
|
};
|
||||||
if (Core::App().settings().groupCallPushToTalkDelay() != delay) {
|
const auto showPrivacyRequest = [=] {
|
||||||
Core::App().settings().setGroupCallPushToTalkDelay(delay);
|
#ifdef Q_OS_MAC
|
||||||
|
if (!Platform::IsMac10_14OrGreater()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto requestInputMonitoring = Platform::IsMac10_15OrGreater();
|
||||||
|
box->getDelegate()->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||||
|
box->addRow(
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
box.get(),
|
||||||
|
rpl::combine(
|
||||||
|
tr::lng_group_call_mac_access(),
|
||||||
|
(requestInputMonitoring
|
||||||
|
? tr::lng_group_call_mac_input()
|
||||||
|
: tr::lng_group_call_mac_accessibility())
|
||||||
|
) | rpl::map([](QString a, QString b) {
|
||||||
|
auto result = Ui::Text::RichLangValue(a);
|
||||||
|
result.append("\n\n").append(Ui::Text::RichLangValue(b));
|
||||||
|
return result;
|
||||||
|
}),
|
||||||
|
st::groupCallBoxLabel),
|
||||||
|
style::margins(
|
||||||
|
st::boxRowPadding.left(),
|
||||||
|
st::boxPadding.top(),
|
||||||
|
st::boxRowPadding.right(),
|
||||||
|
st::boxPadding.bottom()));
|
||||||
|
box->addButton(tr::lng_group_call_mac_settings(), [=] {
|
||||||
|
if (requestInputMonitoring) {
|
||||||
|
Platform::OpenInputMonitoringPrivacySettings();
|
||||||
|
} else {
|
||||||
|
Platform::OpenAccessibilityPrivacySettings();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
|
|
||||||
|
if (!requestInputMonitoring) {
|
||||||
|
// Accessibility is enabled without app restart, so short-poll it.
|
||||||
|
base::timer_each(
|
||||||
|
kCheckAccessibilityInterval
|
||||||
|
) | rpl::filter([] {
|
||||||
|
return base::GlobalShortcutsAllowed();
|
||||||
|
}) | rpl::start_with_next([=] {
|
||||||
|
box->closeBox();
|
||||||
|
}, box->lifetime());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
#endif // Q_OS_MAC
|
||||||
|
};
|
||||||
|
const auto ensureManager = [=] {
|
||||||
|
if (state->manager) {
|
||||||
|
return true;
|
||||||
|
} else if (base::GlobalShortcutsAllowed()) {
|
||||||
|
state->manager = call->ensureGlobalShortcutManager();
|
||||||
|
tryFillFromManager();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
showPrivacyRequest();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
const auto stopRecording = [=] {
|
||||||
|
state->recording = false;
|
||||||
|
state->recordText = tr::lng_group_call_ptt_shortcut();
|
||||||
|
state->shortcutText = state->shortcut
|
||||||
|
? state->shortcut->toDisplayString()
|
||||||
|
: QString();
|
||||||
|
recording->setColorOverride(std::nullopt);
|
||||||
|
if (state->manager) {
|
||||||
|
state->manager->stopRecording();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auto startRecording = [=] {
|
||||||
|
if (!ensureManager()) {
|
||||||
|
state->pushToTalkToggles.fire(false);
|
||||||
|
pushToTalkWrap->hide(anim::type::instant);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state->recording = true;
|
||||||
|
state->recordText = tr::lng_group_call_ptt_recording();
|
||||||
|
recording->setColorOverride(
|
||||||
|
st::groupCallSettingsAttentionButton.textFg->c);
|
||||||
|
auto progress = crl::guard(box, [=](GlobalShortcut shortcut) {
|
||||||
|
state->shortcutText = shortcut->toDisplayString();
|
||||||
|
});
|
||||||
|
auto done = crl::guard(box, [=](GlobalShortcut shortcut) {
|
||||||
|
state->shortcut = shortcut;
|
||||||
|
Core::App().settings().setGroupCallPushToTalkShortcut(shortcut
|
||||||
|
? shortcut->serialize()
|
||||||
|
: QByteArray());
|
||||||
|
applyAndSave();
|
||||||
|
stopRecording();
|
||||||
|
});
|
||||||
|
state->manager->startRecording(std::move(progress), std::move(done));
|
||||||
|
};
|
||||||
|
recording->addClickHandler([=] {
|
||||||
|
if (state->recording) {
|
||||||
|
stopRecording();
|
||||||
|
} else {
|
||||||
|
startRecording();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto label = pushToTalkInner->add(
|
||||||
|
object_ptr<Ui::LabelSimple>(
|
||||||
|
pushToTalkInner,
|
||||||
|
st::groupCallDelayLabel),
|
||||||
|
st::groupCallDelayLabelMargin);
|
||||||
|
const auto value = std::clamp(
|
||||||
|
state->delay,
|
||||||
|
crl::time(0),
|
||||||
|
DelayByIndex(kDelaysCount - 1));
|
||||||
|
const auto callback = [=](crl::time delay) {
|
||||||
|
state->delay = delay;
|
||||||
|
label->setText(tr::lng_group_call_ptt_delay(
|
||||||
|
tr::now,
|
||||||
|
lt_delay,
|
||||||
|
FormatDelay(delay)));
|
||||||
|
if (Core::App().settings().groupCallPushToTalkDelay() != delay) {
|
||||||
|
Core::App().settings().setGroupCallPushToTalkDelay(delay);
|
||||||
|
applyAndSave();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
callback(value);
|
||||||
|
const auto slider = pushToTalkInner->add(
|
||||||
|
object_ptr<Ui::MediaSlider>(
|
||||||
|
pushToTalkInner,
|
||||||
|
st::groupCallDelaySlider),
|
||||||
|
st::groupCallDelayMargin);
|
||||||
|
slider->resize(st::groupCallDelaySlider.seekSize);
|
||||||
|
slider->setPseudoDiscrete(
|
||||||
|
kDelaysCount,
|
||||||
|
DelayByIndex,
|
||||||
|
value,
|
||||||
|
callback);
|
||||||
|
|
||||||
|
pushToTalkWrap->toggle(
|
||||||
|
settings.groupCallPushToTalk(),
|
||||||
|
anim::type::instant);
|
||||||
|
pushToTalk->toggledChanges(
|
||||||
|
) | rpl::start_with_next([=](bool toggled) {
|
||||||
|
if (!toggled) {
|
||||||
|
stopRecording();
|
||||||
|
} else if (!ensureManager()) {
|
||||||
|
state->pushToTalkToggles.fire(false);
|
||||||
|
pushToTalkWrap->hide(anim::type::instant);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Core::App().settings().setGroupCallPushToTalk(toggled);
|
||||||
applyAndSave();
|
applyAndSave();
|
||||||
}
|
pushToTalkWrap->toggle(toggled, anim::type::normal);
|
||||||
};
|
}, pushToTalk->lifetime());
|
||||||
callback(value);
|
|
||||||
const auto slider = pushToTalkInner->add(
|
|
||||||
object_ptr<Ui::MediaSlider>(
|
|
||||||
pushToTalkInner,
|
|
||||||
st::groupCallDelaySlider),
|
|
||||||
st::groupCallDelayMargin);
|
|
||||||
slider->resize(st::groupCallDelaySlider.seekSize);
|
|
||||||
slider->setPseudoDiscrete(
|
|
||||||
kDelaysCount,
|
|
||||||
DelayByIndex,
|
|
||||||
value,
|
|
||||||
callback);
|
|
||||||
|
|
||||||
pushToTalkWrap->toggle(
|
auto boxKeyFilter = [=](not_null<QEvent*> e) {
|
||||||
settings.groupCallPushToTalk(),
|
return (e->type() == QEvent::KeyPress && state->recording)
|
||||||
anim::type::instant);
|
? base::EventFilterResult::Cancel
|
||||||
pushToTalk->toggledChanges(
|
: base::EventFilterResult::Continue;
|
||||||
) | rpl::start_with_next([=](bool toggled) {
|
};
|
||||||
if (!toggled) {
|
box->lifetime().make_state<base::unique_qptr<QObject>>(
|
||||||
stopRecording();
|
base::install_event_filter(box, std::move(boxKeyFilter)));
|
||||||
} else if (!ensureManager()) {
|
}
|
||||||
state->pushToTalkToggles.fire(false);
|
|
||||||
pushToTalkWrap->hide(anim::type::instant);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Core::App().settings().setGroupCallPushToTalk(toggled);
|
|
||||||
applyAndSave();
|
|
||||||
pushToTalkWrap->toggle(toggled, anim::type::normal);
|
|
||||||
}, pushToTalk->lifetime());
|
|
||||||
|
|
||||||
auto boxKeyFilter = [=](not_null<QEvent*> e) {
|
AddSkip(layout);
|
||||||
return (e->type() == QEvent::KeyPress && state->recording)
|
//AddDivider(layout);
|
||||||
? base::EventFilterResult::Cancel
|
//AddSkip(layout);
|
||||||
: base::EventFilterResult::Continue;
|
|
||||||
};
|
|
||||||
box->lifetime().make_state<base::unique_qptr<QObject>>(
|
|
||||||
base::install_event_filter(box, std::move(boxKeyFilter)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AddSkip(layout);
|
|
||||||
//AddDivider(layout);
|
|
||||||
//AddSkip(layout);
|
|
||||||
|
|
||||||
auto shareLink = Fn<void()>();
|
auto shareLink = Fn<void()>();
|
||||||
if (peer->isChannel()
|
if (peer->isChannel()
|
||||||
&& peer->asChannel()->hasUsername()
|
&& peer->asChannel()->hasUsername()
|
||||||
|
@ -644,15 +645,17 @@ void SettingsBox(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
box->setShowFinishedCallback([=] {
|
if (!rtmp) {
|
||||||
// Means we finished showing the box.
|
box->setShowFinishedCallback([=] {
|
||||||
crl::on_main(box, [=] {
|
// Means we finished showing the box.
|
||||||
state->micTester = std::make_unique<Webrtc::AudioInputTester>(
|
crl::on_main(box, [=] {
|
||||||
Core::App().settings().callAudioBackend(),
|
state->micTester = std::make_unique<Webrtc::AudioInputTester>(
|
||||||
Core::App().settings().callInputDeviceId());
|
Core::App().settings().callAudioBackend(),
|
||||||
state->levelUpdateTimer.callEach(kMicTestUpdateInterval);
|
Core::App().settings().callInputDeviceId());
|
||||||
|
state->levelUpdateTimer.callEach(kMicTestUpdateInterval);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
box->setTitle(tr::lng_group_call_settings_title());
|
box->setTitle(tr::lng_group_call_settings_title());
|
||||||
box->boxClosing(
|
box->boxClosing(
|
||||||
|
|
|
@ -876,6 +876,9 @@ rpl::producer<QString> MuteButtonTooltip(not_null<GroupCall*> call) {
|
||||||
// : tr::lng_group_call_set_reminder();
|
// : tr::lng_group_call_set_reminder();
|
||||||
// }) | rpl::flatten_latest();
|
// }) | rpl::flatten_latest();
|
||||||
// }
|
// }
|
||||||
|
if (call->rtmp()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
return call->mutedValue(
|
return call->mutedValue(
|
||||||
) | rpl::map([](MuteState muted) {
|
) | rpl::map([](MuteState muted) {
|
||||||
switch (muted) {
|
switch (muted) {
|
||||||
|
|
|
@ -492,7 +492,7 @@ void GroupCall::processQueuedUpdates() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupCall::computeParticipantsCount() {
|
void GroupCall::computeParticipantsCount() {
|
||||||
_fullCount = _allParticipantsLoaded
|
_fullCount = (_allParticipantsLoaded && !_listenersHidden)
|
||||||
? int(_participants.size())
|
? int(_participants.size())
|
||||||
: std::max(int(_participants.size()), _serverParticipantsCount);
|
: std::max(int(_participants.size()), _serverParticipantsCount);
|
||||||
}
|
}
|
||||||
|
|
|
@ -825,7 +825,17 @@ void CallMuteButton::init() {
|
||||||
) | rpl::start_with_next([=](QRect clip) {
|
) | rpl::start_with_next([=](QRect clip) {
|
||||||
Painter p(_content);
|
Painter p(_content);
|
||||||
|
|
||||||
_icons[_iconState.index]->paint(p, _muteIconRect.x(), _muteIconRect.y());
|
const auto expand = _state.current().expandType;
|
||||||
|
if (expand == CallMuteButtonExpandType::Expanded) {
|
||||||
|
st::callMuteFromFullScreen.paintInCenter(p, _muteIconRect);
|
||||||
|
} else if (expand == CallMuteButtonExpandType::Normal) {
|
||||||
|
st::callMuteToFullScreen.paintInCenter(p, _muteIconRect);
|
||||||
|
} else {
|
||||||
|
_icons[_iconState.index]->paint(
|
||||||
|
p,
|
||||||
|
_muteIconRect.x(),
|
||||||
|
_muteIconRect.y());
|
||||||
|
}
|
||||||
|
|
||||||
if (_radialInfo.state.has_value() && _switchAnimation.animating()) {
|
if (_radialInfo.state.has_value() && _switchAnimation.animating()) {
|
||||||
const auto radialProgress = _radialInfo.realShowProgress;
|
const auto radialProgress = _radialInfo.realShowProgress;
|
||||||
|
|
|
@ -43,11 +43,18 @@ enum class CallMuteButtonType {
|
||||||
ScheduledNotify,
|
ScheduledNotify,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CallMuteButtonExpandType {
|
||||||
|
None,
|
||||||
|
Normal,
|
||||||
|
Expanded,
|
||||||
|
};
|
||||||
|
|
||||||
struct CallMuteButtonState {
|
struct CallMuteButtonState {
|
||||||
QString text;
|
QString text;
|
||||||
QString subtext;
|
QString subtext;
|
||||||
QString tooltip;
|
QString tooltip;
|
||||||
CallMuteButtonType type = CallMuteButtonType::Connecting;
|
CallMuteButtonType type = CallMuteButtonType::Connecting;
|
||||||
|
CallMuteButtonExpandType expandType = CallMuteButtonExpandType::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CallMuteButton final : private AbstractTooltipShower {
|
class CallMuteButton final : private AbstractTooltipShower {
|
||||||
|
|
Loading…
Add table
Reference in a new issue