mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Add a hint to turn on the camera.
This commit is contained in:
parent
5827d6ffdb
commit
1cb1f1cbc1
9 changed files with 293 additions and 79 deletions
BIN
Telegram/Resources/icons/calls/video_tooltip.png
Normal file
BIN
Telegram/Resources/icons/calls/video_tooltip.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 360 B |
BIN
Telegram/Resources/icons/calls/video_tooltip@2x.png
Normal file
BIN
Telegram/Resources/icons/calls/video_tooltip@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 622 B |
BIN
Telegram/Resources/icons/calls/video_tooltip@3x.png
Normal file
BIN
Telegram/Resources/icons/calls/video_tooltip@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 967 B |
|
@ -1251,7 +1251,7 @@ groupCallTooltip: Tooltip(defaultTooltip) {
|
|||
}
|
||||
groupCallNiceTooltip: ImportantTooltip(defaultImportantTooltip) {
|
||||
bg: importantTooltipBg;
|
||||
padding: margins(10px, 3px, 10px, 5px);
|
||||
padding: margins(10px, 1px, 10px, 3px);
|
||||
radius: 4px;
|
||||
arrow: 4px;
|
||||
}
|
||||
|
@ -1262,5 +1262,16 @@ groupCallNiceTooltipLabel: FlatLabel(defaultImportantTooltipLabel) {
|
|||
linkFontOver: font(11px underline);
|
||||
}
|
||||
}
|
||||
groupCallStickedTooltip: ImportantTooltip(groupCallNiceTooltip) {
|
||||
padding: margins(10px, 1px, 6px, 3px);
|
||||
}
|
||||
groupCallStickedTooltipClose: IconButton(defaultIconButton) {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
iconPosition: point(4px, 3px);
|
||||
icon: icon {{ "calls/video_tooltip", importantTooltipFg }};
|
||||
iconOver: icon {{ "calls/video_tooltip", importantTooltipFg }};
|
||||
ripple: emptyRippleAnimation;
|
||||
}
|
||||
groupCallNiceTooltipTop: 4px;
|
||||
groupCallPaused: icon {{ "calls/video_large_paused", groupCallVideoTextFg }};
|
||||
|
|
|
@ -187,6 +187,28 @@ struct GroupCall::SinkPointer {
|
|||
std::weak_ptr<Webrtc::SinkInterface> data;
|
||||
};
|
||||
|
||||
struct GroupCall::VideoTrack {
|
||||
VideoTrack(bool paused, bool requireARGB32, not_null<PeerData*> peer);
|
||||
|
||||
Webrtc::VideoTrack track;
|
||||
rpl::variable<QSize> trackSize;
|
||||
not_null<PeerData*> peer;
|
||||
rpl::lifetime lifetime;
|
||||
Group::VideoQuality quality = Group::VideoQuality();
|
||||
bool shown = false;
|
||||
};
|
||||
|
||||
GroupCall::VideoTrack::VideoTrack(
|
||||
bool paused,
|
||||
bool requireARGB32,
|
||||
not_null<PeerData*> peer)
|
||||
: track((paused
|
||||
? Webrtc::VideoState::Paused
|
||||
: Webrtc::VideoState::Active),
|
||||
requireARGB32)
|
||||
, peer(peer) {
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsGroupCallAdmin(
|
||||
not_null<PeerData*> peer,
|
||||
not_null<PeerData*> participantPeer) {
|
||||
|
@ -451,6 +473,21 @@ void GroupCall::MediaChannelDescriptionsTask::cancel() {
|
|||
}
|
||||
}
|
||||
|
||||
not_null<PeerData*> GroupCall::TrackPeer(
|
||||
const std::unique_ptr<VideoTrack> &track) {
|
||||
return track->peer;
|
||||
}
|
||||
|
||||
not_null<Webrtc::VideoTrack*> GroupCall::TrackPointer(
|
||||
const std::unique_ptr<VideoTrack> &track) {
|
||||
return &track->track;
|
||||
}
|
||||
|
||||
rpl::producer<QSize> GroupCall::TrackSizeValue(
|
||||
const std::unique_ptr<VideoTrack> &track) {
|
||||
return track->trackSize.value();
|
||||
}
|
||||
|
||||
GroupCall::GroupCall(
|
||||
not_null<Delegate*> delegate,
|
||||
Group::JoinInfo info,
|
||||
|
@ -1064,43 +1101,39 @@ void GroupCall::markEndpointActive(
|
|||
if (active) {
|
||||
const auto i = _activeVideoTracks.emplace(
|
||||
endpoint,
|
||||
VideoTrack{
|
||||
.track = std::make_unique<Webrtc::VideoTrack>(
|
||||
(paused
|
||||
? Webrtc::VideoState::Paused
|
||||
: Webrtc::VideoState::Active),
|
||||
_requireARGB32),
|
||||
.peer = endpoint.peer,
|
||||
}).first;
|
||||
const auto track = i->second.track.get();
|
||||
std::make_unique<VideoTrack>(
|
||||
paused,
|
||||
_requireARGB32,
|
||||
endpoint.peer)).first;
|
||||
const auto track = &i->second->track;
|
||||
|
||||
track->renderNextFrame(
|
||||
) | rpl::start_with_next([=] {
|
||||
auto &activeTrack = _activeVideoTracks[endpoint];
|
||||
const auto activeTrack = _activeVideoTracks[endpoint].get();
|
||||
const auto size = track->frameSize();
|
||||
if (size.isEmpty()) {
|
||||
track->markFrameShown();
|
||||
} else if (!activeTrack.shown) {
|
||||
activeTrack.shown = true;
|
||||
} else if (!activeTrack->shown) {
|
||||
activeTrack->shown = true;
|
||||
markTrackShown(endpoint, true);
|
||||
}
|
||||
activeTrack.trackSize = size;
|
||||
}, i->second.lifetime);
|
||||
activeTrack->trackSize = size;
|
||||
}, i->second->lifetime);
|
||||
|
||||
const auto size = track->frameSize();
|
||||
i->second.trackSize = size;
|
||||
i->second->trackSize = size;
|
||||
if (!size.isEmpty() || paused) {
|
||||
i->second.shown = true;
|
||||
i->second->shown = true;
|
||||
shown = true;
|
||||
} else {
|
||||
track->stateValue(
|
||||
) | rpl::filter([=](Webrtc::VideoState state) {
|
||||
return (state == Webrtc::VideoState::Paused)
|
||||
&& !_activeVideoTracks[endpoint].shown;
|
||||
&& !_activeVideoTracks[endpoint]->shown;
|
||||
}) | rpl::start_with_next([=] {
|
||||
_activeVideoTracks[endpoint].shown = true;
|
||||
_activeVideoTracks[endpoint]->shown = true;
|
||||
markTrackShown(endpoint, true);
|
||||
}, i->second.lifetime);
|
||||
}, i->second->lifetime);
|
||||
}
|
||||
addVideoOutput(i->first.id, { track->sink() });
|
||||
} else {
|
||||
|
@ -1144,7 +1177,7 @@ void GroupCall::markTrackPaused(const VideoEndpoint &endpoint, bool paused) {
|
|||
const auto i = _activeVideoTracks.find(endpoint);
|
||||
Assert(i != end(_activeVideoTracks));
|
||||
|
||||
i->second.track->setState(paused
|
||||
i->second->track.setState(paused
|
||||
? Webrtc::VideoState::Paused
|
||||
: Webrtc::VideoState::Active);
|
||||
}
|
||||
|
@ -2420,13 +2453,13 @@ void GroupCall::updateRequestedVideoChannels() {
|
|||
.ssrcGroups = (params->camera.endpointId == endpointId
|
||||
? params->camera.ssrcGroups
|
||||
: params->screen.ssrcGroups),
|
||||
.minQuality = ((video.quality == Group::VideoQuality::Full
|
||||
.minQuality = ((video->quality == Group::VideoQuality::Full
|
||||
&& endpoint.type == VideoEndpointType::Screen)
|
||||
? Quality::Full
|
||||
: Quality::Thumbnail),
|
||||
.maxQuality = ((video.quality == Group::VideoQuality::Full)
|
||||
.maxQuality = ((video->quality == Group::VideoQuality::Full)
|
||||
? Quality::Full
|
||||
: (video.quality == Group::VideoQuality::Medium
|
||||
: (video->quality == Group::VideoQuality::Medium
|
||||
&& endpoint.type != VideoEndpointType::Screen)
|
||||
? Quality::Medium
|
||||
: Quality::Thumbnail),
|
||||
|
@ -2911,10 +2944,10 @@ void GroupCall::requestVideoQuality(
|
|||
return;
|
||||
}
|
||||
const auto i = _activeVideoTracks.find(endpoint);
|
||||
if (i == end(_activeVideoTracks) || i->second.quality == quality) {
|
||||
if (i == end(_activeVideoTracks) || i->second->quality == quality) {
|
||||
return;
|
||||
}
|
||||
i->second.quality = quality;
|
||||
i->second->quality = quality;
|
||||
updateRequestedVideoChannelsDelayed();
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,8 @@ struct VideoEndpoint {
|
|||
std::string id;
|
||||
|
||||
[[nodiscard]] bool empty() const noexcept {
|
||||
Expects(id.empty() || peer != nullptr);
|
||||
|
||||
return id.empty();
|
||||
}
|
||||
[[nodiscard]] explicit operator bool() const noexcept {
|
||||
|
@ -194,6 +196,15 @@ public:
|
|||
|
||||
using GlobalShortcutManager = base::GlobalShortcutManager;
|
||||
|
||||
struct VideoTrack;
|
||||
|
||||
[[nodiscard]] static not_null<PeerData*> TrackPeer(
|
||||
const std::unique_ptr<VideoTrack> &track);
|
||||
[[nodiscard]] static not_null<Webrtc::VideoTrack*> TrackPointer(
|
||||
const std::unique_ptr<VideoTrack> &track);
|
||||
[[nodiscard]] static rpl::producer<QSize> TrackSizeValue(
|
||||
const std::unique_ptr<VideoTrack> &track);
|
||||
|
||||
GroupCall(
|
||||
not_null<Delegate*> delegate,
|
||||
Group::JoinInfo info,
|
||||
|
@ -321,27 +332,8 @@ public:
|
|||
-> rpl::producer<VideoEndpoint> {
|
||||
return _videoEndpointLarge.value();
|
||||
}
|
||||
|
||||
struct VideoTrack {
|
||||
std::unique_ptr<Webrtc::VideoTrack> track;
|
||||
rpl::variable<QSize> trackSize;
|
||||
PeerData *peer = nullptr;
|
||||
rpl::lifetime lifetime;
|
||||
Group::VideoQuality quality = Group::VideoQuality();
|
||||
bool shown = false;
|
||||
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return (track != nullptr);
|
||||
}
|
||||
[[nodiscard]] bool operator==(const VideoTrack &other) const {
|
||||
return (track == other.track) && (peer == other.peer);
|
||||
}
|
||||
[[nodiscard]] bool operator!=(const VideoTrack &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
[[nodiscard]] auto activeVideoTracks() const
|
||||
-> const base::flat_map<VideoEndpoint, VideoTrack> & {
|
||||
-> const base::flat_map<VideoEndpoint, std::unique_ptr<VideoTrack>> & {
|
||||
return _activeVideoTracks;
|
||||
}
|
||||
[[nodiscard]] auto shownVideoTracks() const
|
||||
|
@ -625,7 +617,9 @@ private:
|
|||
rpl::event_stream<VideoStateToggle> _videoStreamActiveUpdates;
|
||||
rpl::event_stream<VideoStateToggle> _videoStreamPausedUpdates;
|
||||
rpl::event_stream<VideoStateToggle> _videoStreamShownUpdates;
|
||||
base::flat_map<VideoEndpoint, VideoTrack> _activeVideoTracks;
|
||||
base::flat_map<
|
||||
VideoEndpoint,
|
||||
std::unique_ptr<VideoTrack>> _activeVideoTracks;
|
||||
base::flat_set<VideoEndpoint> _shownVideoTracks;
|
||||
rpl::variable<VideoEndpoint> _videoEndpointLarge;
|
||||
rpl::variable<bool> _videoEndpointPinned = false;
|
||||
|
|
|
@ -499,17 +499,26 @@ void Panel::refreshVideoButtons(std::optional<bool> overrideWideMode) {
|
|||
&st::groupCallVideoActiveSmall);
|
||||
_video->show();
|
||||
_video->setClickedCallback([=] {
|
||||
hideStickedTooltip(
|
||||
StickedTooltip::Camera,
|
||||
StickedTooltipHide::Activated);
|
||||
_call->toggleVideo(!_call->isSharingCamera());
|
||||
});
|
||||
_video->setColorOverrides(
|
||||
toggleableOverrides(_call->isSharingCameraValue()));
|
||||
_call->isSharingCameraValue(
|
||||
) | rpl::start_with_next([=](bool sharing) {
|
||||
if (sharing) {
|
||||
hideStickedTooltip(
|
||||
StickedTooltip::Camera,
|
||||
StickedTooltipHide::Activated);
|
||||
}
|
||||
_video->setProgress(sharing ? 1. : 0.);
|
||||
}, _video->lifetime());
|
||||
_call->mutedValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
updateButtonsGeometry();
|
||||
showStickedTooltip();
|
||||
}, _video->lifetime());
|
||||
}
|
||||
if (!_screenShare) {
|
||||
|
@ -536,6 +545,45 @@ void Panel::refreshVideoButtons(std::optional<bool> overrideWideMode) {
|
|||
updateButtonsGeometry();
|
||||
}
|
||||
|
||||
void Panel::hideStickedTooltip(StickedTooltipHide hide) {
|
||||
if (!_stickedTooltipClose || !_niceTooltipControl) {
|
||||
return;
|
||||
}
|
||||
if (_niceTooltipControl.data() == _video.data()) {
|
||||
hideStickedTooltip(StickedTooltip::Camera, hide);
|
||||
} else if (_niceTooltipControl.data() == _mute->outer().get()) {
|
||||
hideStickedTooltip(StickedTooltip::Microphone, hide);
|
||||
}
|
||||
}
|
||||
|
||||
void Panel::hideStickedTooltip(
|
||||
StickedTooltip type,
|
||||
StickedTooltipHide hide) {
|
||||
if (hide != StickedTooltipHide::Unavailable) {
|
||||
_stickedTooltipsShown |= type;
|
||||
if (hide == StickedTooltipHide::Discarded) {
|
||||
// #TODO calls save to settings.
|
||||
}
|
||||
}
|
||||
const auto control = (type == StickedTooltip::Camera)
|
||||
? _video.data()
|
||||
: (type == StickedTooltip::Microphone)
|
||||
? _mute->outer().get()
|
||||
: nullptr;
|
||||
if (_niceTooltipControl.data() == control) {
|
||||
hideNiceTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
void Panel::hideNiceTooltip() {
|
||||
if (!_niceTooltip) {
|
||||
return;
|
||||
}
|
||||
_stickedTooltipClose = nullptr;
|
||||
_niceTooltip.release()->toggleAnimated(false);
|
||||
_niceTooltipControl = nullptr;
|
||||
}
|
||||
|
||||
void Panel::initShareAction() {
|
||||
const auto showBoxCallback = [=](object_ptr<Ui::BoxContent> next) {
|
||||
_layerBg->showBox(std::move(next));
|
||||
|
@ -843,9 +891,9 @@ void Panel::raiseControls() {
|
|||
void Panel::setupVideo(not_null<Viewport*> viewport) {
|
||||
const auto setupTile = [=](
|
||||
const VideoEndpoint &endpoint,
|
||||
const GroupCall::VideoTrack &track) {
|
||||
const std::unique_ptr<GroupCall::VideoTrack> &track) {
|
||||
using namespace rpl::mappers;
|
||||
const auto row = _members->lookupRow(track.peer);
|
||||
const auto row = _members->lookupRow(GroupCall::TrackPeer(track));
|
||||
Assert(row != nullptr);
|
||||
auto pinned = rpl::combine(
|
||||
_call->videoEndpointLargeValue(),
|
||||
|
@ -853,8 +901,8 @@ void Panel::setupVideo(not_null<Viewport*> viewport) {
|
|||
) | rpl::map(_1 == endpoint && _2);
|
||||
viewport->add(
|
||||
endpoint,
|
||||
VideoTileTrack{ track.track.get(), row },
|
||||
track.trackSize.value(),
|
||||
VideoTileTrack{ GroupCall::TrackPointer(track), row },
|
||||
GroupCall::TrackSizeValue(track),
|
||||
std::move(pinned));
|
||||
};
|
||||
for (const auto &[endpoint, track] : _call->activeVideoTracks()) {
|
||||
|
@ -908,18 +956,24 @@ void Panel::toggleWideControls(bool shown) {
|
|||
}
|
||||
_showWideControls = shown;
|
||||
crl::on_main(widget(), [=] {
|
||||
if (_wideControlsShown == _showWideControls) {
|
||||
return;
|
||||
}
|
||||
_wideControlsShown = _showWideControls;
|
||||
_wideControlsAnimation.start(
|
||||
[=] { updateButtonsGeometry(); },
|
||||
_wideControlsShown ? 0. : 1.,
|
||||
_wideControlsShown ? 1. : 0.,
|
||||
st::slideWrapDuration);
|
||||
updateWideControlsVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
void Panel::updateWideControlsVisibility() {
|
||||
const auto shown = _showWideControls
|
||||
|| (_stickedTooltipClose != nullptr);
|
||||
if (_wideControlsShown == shown) {
|
||||
return;
|
||||
}
|
||||
_wideControlsShown = shown;
|
||||
_wideControlsAnimation.start(
|
||||
[=] { updateButtonsGeometry(); },
|
||||
_wideControlsShown ? 0. : 1.,
|
||||
_wideControlsShown ? 1. : 0.,
|
||||
st::slideWrapDuration);
|
||||
}
|
||||
|
||||
void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
||||
const auto validateRecordingMark = [=](bool recording) {
|
||||
if (!recording && _recordingMark) {
|
||||
|
@ -988,6 +1042,7 @@ void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
|
|||
_call->isSharingCameraValue()
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshVideoButtons();
|
||||
showStickedTooltip();
|
||||
}, widget()->lifetime());
|
||||
|
||||
rpl::combine(
|
||||
|
@ -1373,6 +1428,7 @@ bool Panel::updateMode() {
|
|||
updateButtonsStyles();
|
||||
refreshControlsBackground();
|
||||
updateControlsGeometry();
|
||||
showStickedTooltip();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1557,8 +1613,12 @@ void Panel::trackControl(Ui::RpWidget *widget, rpl::lifetime &lifetime) {
|
|||
}
|
||||
|
||||
void Panel::trackControlOver(not_null<Ui::RpWidget*> control, bool over) {
|
||||
if (_niceTooltip) {
|
||||
_niceTooltip.release()->toggleAnimated(false);
|
||||
if (_stickedTooltipClose) {
|
||||
if (!over) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
hideNiceTooltip();
|
||||
}
|
||||
if (over) {
|
||||
Ui::Integration::Instance().registerLeaveSubscription(control);
|
||||
|
@ -1569,7 +1629,37 @@ void Panel::trackControlOver(not_null<Ui::RpWidget*> control, bool over) {
|
|||
toggleWideControls(over);
|
||||
}
|
||||
|
||||
void Panel::showNiceTooltip(not_null<Ui::RpWidget*> control) {
|
||||
void Panel::showStickedTooltip() {
|
||||
static const auto kHasCamera = !Webrtc::GetVideoInputList().empty();
|
||||
if (!(_stickedTooltipsShown & StickedTooltip::Camera)
|
||||
&& (_mode.current() == PanelMode::Wide)
|
||||
&& _video
|
||||
&& _call->videoIsWorking()
|
||||
&& !_call->mutedByAdmin()
|
||||
&& kHasCamera) { // Don't recount this every time for now.
|
||||
showNiceTooltip(_video, NiceTooltipType::Sticked);
|
||||
return;
|
||||
}
|
||||
hideStickedTooltip(
|
||||
StickedTooltip::Camera,
|
||||
StickedTooltipHide::Unavailable);
|
||||
|
||||
if (!(_stickedTooltipsShown & StickedTooltip::Microphone)
|
||||
&& (_mode.current() == PanelMode::Wide)
|
||||
&& _mute
|
||||
&& !_call->mutedByAdmin()
|
||||
&& false) { // Check if there is incoming sound.
|
||||
showNiceTooltip(_mute->outer(), NiceTooltipType::Sticked);
|
||||
return;
|
||||
}
|
||||
hideStickedTooltip(
|
||||
StickedTooltip::Microphone,
|
||||
StickedTooltipHide::Unavailable);
|
||||
}
|
||||
|
||||
void Panel::showNiceTooltip(
|
||||
not_null<Ui::RpWidget*> control,
|
||||
NiceTooltipType type) {
|
||||
auto text = [&]() -> rpl::producer<QString> {
|
||||
if (control == _screenShare.data()) {
|
||||
if (_call->mutedByAdmin()) {
|
||||
|
@ -1597,38 +1687,95 @@ void Panel::showNiceTooltip(not_null<Ui::RpWidget*> control) {
|
|||
}();
|
||||
if (!text
|
||||
|| _wideControlsAnimation.animating()
|
||||
|| !_wideControlsShown) {
|
||||
|| !_wideControlsShown
|
||||
|| _stickedTooltipClose) {
|
||||
return;
|
||||
}
|
||||
const auto inner = [&]() -> Ui::RpWidget* {
|
||||
const auto normal = (type == NiceTooltipType::Normal);
|
||||
auto container = normal
|
||||
? nullptr
|
||||
: Ui::CreateChild<Ui::RpWidget>(widget().get());
|
||||
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
||||
(normal ? widget().get() : container),
|
||||
std::move(text),
|
||||
st::groupCallNiceTooltipLabel);
|
||||
if (normal) {
|
||||
return label;
|
||||
}
|
||||
const auto button = Ui::CreateChild<Ui::IconButton>(
|
||||
container,
|
||||
st::groupCallStickedTooltipClose);
|
||||
rpl::combine(
|
||||
label->sizeValue(),
|
||||
button->sizeValue()
|
||||
) | rpl::start_with_next([=](QSize text, QSize close) {
|
||||
const auto height = std::max(text.height(), close.height());
|
||||
container->resize(text.width() + close.width(), height);
|
||||
label->move(0, (height - text.height()) / 2);
|
||||
button->move(text.width(), (height - close.height()) / 2);
|
||||
}, container->lifetime());
|
||||
button->setClickedCallback([=] {
|
||||
hideStickedTooltip(StickedTooltipHide::Discarded);
|
||||
});
|
||||
_stickedTooltipClose = button;
|
||||
updateWideControlsVisibility();
|
||||
return container;
|
||||
}();
|
||||
_niceTooltip.create(
|
||||
widget().get(),
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
widget().get(),
|
||||
std::move(text),
|
||||
st::groupCallNiceTooltipLabel),
|
||||
st::groupCallNiceTooltip);
|
||||
object_ptr<Ui::RpWidget>::fromRaw(inner),
|
||||
(type == NiceTooltipType::Sticked
|
||||
? st::groupCallStickedTooltip
|
||||
: st::groupCallNiceTooltip));
|
||||
const auto tooltip = _niceTooltip.data();
|
||||
const auto weak = QPointer<QWidget>(tooltip);
|
||||
const auto destroy = [=] {
|
||||
delete weak.data();
|
||||
};
|
||||
tooltip->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
if (type != NiceTooltipType::Sticked) {
|
||||
tooltip->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
}
|
||||
tooltip->setHiddenCallback(destroy);
|
||||
base::qt_signal_producer(
|
||||
control.get(),
|
||||
&QObject::destroyed
|
||||
) | rpl::start_with_next(destroy, tooltip->lifetime());
|
||||
|
||||
const auto geometry = control->geometry();
|
||||
_niceTooltipControl = control;
|
||||
updateTooltipGeometry();
|
||||
tooltip->toggleAnimated(true);
|
||||
}
|
||||
|
||||
void Panel::updateTooltipGeometry() {
|
||||
if (!_niceTooltip) {
|
||||
return;
|
||||
} else if (!_niceTooltipControl) {
|
||||
hideNiceTooltip();
|
||||
return;
|
||||
}
|
||||
const auto geometry = _niceTooltipControl->geometry();
|
||||
const auto weak = QPointer<QWidget>(_niceTooltip);
|
||||
const auto countPosition = [=](QSize size) {
|
||||
const auto strong = weak.data();
|
||||
if (!strong) {
|
||||
return QPoint();
|
||||
}
|
||||
const auto wide = (_mode.current() == PanelMode::Wide);
|
||||
const auto top = geometry.y()
|
||||
- st::groupCallNiceTooltipTop
|
||||
- (wide ? st::groupCallNiceTooltipTop : 0)
|
||||
- size.height();
|
||||
const auto middle = geometry.center().x();
|
||||
if (!strong) {
|
||||
return QPoint();
|
||||
} else if (!wide) {
|
||||
return QPoint(
|
||||
std::max(
|
||||
std::min(
|
||||
middle - size.width() / 2,
|
||||
(widget()->width()
|
||||
- st::groupCallMembersMargin.right()
|
||||
- size.width())),
|
||||
st::groupCallMembersMargin.left()),
|
||||
top);
|
||||
}
|
||||
const auto back = _controlsBackgroundWide.data();
|
||||
if (size.width() >= _viewport->widget()->width()) {
|
||||
return QPoint(_viewport->widget()->x(), top);
|
||||
|
@ -1645,8 +1792,7 @@ void Panel::showNiceTooltip(not_null<Ui::RpWidget*> control) {
|
|||
return QPoint(middle - size.width() / 2, top);
|
||||
}
|
||||
};
|
||||
tooltip->pointAt(geometry, RectPart::Top, countPosition);
|
||||
tooltip->toggleAnimated(true);
|
||||
_niceTooltip->pointAt(geometry, RectPart::Top, countPosition);
|
||||
}
|
||||
|
||||
void Panel::trackControls(bool track) {
|
||||
|
@ -1832,6 +1978,7 @@ void Panel::updateButtonsGeometry() {
|
|||
width,
|
||||
st::groupCallMembersBottomSkip);
|
||||
}
|
||||
updateTooltipGeometry();
|
||||
}
|
||||
|
||||
bool Panel::videoButtonInNarrowMode() const {
|
||||
|
|
|
@ -84,6 +84,24 @@ private:
|
|||
using State = GroupCall::State;
|
||||
struct ControlsBackgroundNarrow;
|
||||
|
||||
enum class NiceTooltipType {
|
||||
Normal,
|
||||
Sticked,
|
||||
};
|
||||
enum class StickedTooltip {
|
||||
Camera = 0x01,
|
||||
Microphone = 0x02,
|
||||
};
|
||||
friend constexpr inline bool is_flag_type(StickedTooltip) {
|
||||
return true;
|
||||
};
|
||||
using StickedTooltips = base::flags<StickedTooltip>;
|
||||
enum class StickedTooltipHide {
|
||||
Unavailable,
|
||||
Activated,
|
||||
Discarded,
|
||||
};
|
||||
|
||||
std::unique_ptr<Ui::Window> createWindow();
|
||||
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
|
||||
|
||||
|
@ -111,11 +129,18 @@ private:
|
|||
|
||||
void trackControl(Ui::RpWidget *widget, rpl::lifetime &lifetime);
|
||||
void trackControlOver(not_null<Ui::RpWidget*> control, bool over);
|
||||
void showNiceTooltip(not_null<Ui::RpWidget*> control);
|
||||
void showNiceTooltip(
|
||||
not_null<Ui::RpWidget*> control,
|
||||
NiceTooltipType type = NiceTooltipType::Normal);
|
||||
void showStickedTooltip();
|
||||
void hideStickedTooltip(StickedTooltipHide hide);
|
||||
void hideStickedTooltip(StickedTooltip type, StickedTooltipHide hide);
|
||||
void hideNiceTooltip();
|
||||
|
||||
bool updateMode();
|
||||
void updateControlsGeometry();
|
||||
void updateButtonsGeometry();
|
||||
void updateTooltipGeometry();
|
||||
void updateButtonsStyles();
|
||||
void updateMembersGeometry();
|
||||
void refreshControlsBackground();
|
||||
|
@ -127,6 +152,7 @@ private:
|
|||
std::optional<bool> overrideWideMode = std::nullopt);
|
||||
void refreshTopButton();
|
||||
void toggleWideControls(bool shown);
|
||||
void updateWideControlsVisibility();
|
||||
[[nodiscard]] bool videoButtonInNarrowMode() const;
|
||||
|
||||
void endCall();
|
||||
|
@ -202,6 +228,9 @@ private:
|
|||
std::unique_ptr<Ui::CallMuteButton> _mute;
|
||||
object_ptr<Ui::CallButton> _hangup;
|
||||
object_ptr<Ui::ImportantTooltip> _niceTooltip = { nullptr };
|
||||
QPointer<Ui::IconButton> _stickedTooltipClose;
|
||||
QPointer<Ui::RpWidget> _niceTooltipControl;
|
||||
StickedTooltips _stickedTooltipsShown;
|
||||
Fn<void()> _callShareLinkCallback;
|
||||
|
||||
const std::unique_ptr<Toasts> _toasts;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d8abc60245236e388206e2021bfeb58e83e504fc
|
||||
Subproject commit 825ef11f1a5c6b00cd571c24525c84dca431eaa2
|
Loading…
Add table
Reference in a new issue