Add tooltips for wide mode controls.

This commit is contained in:
John Preston 2021-05-28 19:08:11 +04:00
parent 9a9430b5e1
commit 3f2b473287
11 changed files with 188 additions and 43 deletions

View file

@ -1260,3 +1260,17 @@ groupCallTooltip: Tooltip(defaultTooltip) {
textFg: groupCallMembersFg;
textBorder: groupCallMembersBgOver;
}
groupCallNiceTooltip: ImportantTooltip(defaultImportantTooltip) {
bg: importantTooltipBg;
padding: margins(10px, 3px, 10px, 5px);
radius: 4px;
arrow: 4px;
}
groupCallNiceTooltipLabel: FlatLabel(defaultImportantTooltipLabel) {
style: TextStyle(defaultTextStyle) {
font: font(11px);
linkFont: font(11px);
linkFontOver: font(11px underline);
}
}
groupCallNiceTooltipTop: 4px;

View file

@ -500,7 +500,6 @@ rpl::producer<bool> GroupCall::canManageValue() const {
void GroupCall::toggleVideo(bool active) {
if (!_instance
|| !_id
|| (active && mutedByAdmin())
|| (!active && !_cameraOutgoing)) {
return;
}
@ -513,7 +512,6 @@ void GroupCall::toggleVideo(bool active) {
void GroupCall::toggleScreenSharing(std::optional<QString> uniqueId) {
if (!_instance
|| !_id
|| (uniqueId && mutedByAdmin())
|| (!uniqueId && !_screenOutgoing)) {
return;
}

View file

@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/checkbox.h"
#include "ui/widgets/dropdown_menu.h"
#include "ui/widgets/input_fields.h"
#include "ui/widgets/tooltip.h"
#include "ui/chat/group_call_bar.h"
#include "ui/layers/layer_manager.h"
#include "ui/layers/generic_box.h"
@ -45,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/peer_lists_box.h"
#include "boxes/confirm_box.h"
#include "base/unixtime.h"
#include "base/qt_signal_producer.h"
#include "base/timer_rpl.h"
#include "app.h"
#include "apiwrap.h" // api().kickParticipant.
@ -1792,6 +1794,7 @@ bool Panel::updateMode() {
_call->pinVideoEndpoint({});
}
refreshVideoButtons(wide);
_niceTooltip.destroy();
_mode = mode;
if (_title) {
_title->setTextColorOverride(wide
@ -1983,33 +1986,111 @@ void Panel::setupControlsBackgroundWide() {
trackControls(true);
}
template <typename WidgetPointer>
void Panel::trackControl(WidgetPointer &widget, rpl::lifetime &lifetime) {
if (widget) {
const auto raw = &*widget;
raw->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) {
using Type = std::remove_cvref_t<decltype(*raw)>;
constexpr auto mute = std::is_same_v<Type, Ui::CallMuteButton>;
if (e->type() == QEvent::Enter) {
auto &integration = Ui::Integration::Instance();
if constexpr (mute) {
integration.registerLeaveSubscription(raw->outer());
} else {
integration.registerLeaveSubscription(raw);
}
toggleWideControls(true);
} else if (e->type() == QEvent::Leave) {
auto &integration = Ui::Integration::Instance();
if constexpr (mute) {
integration.unregisterLeaveSubscription(raw->outer());
} else {
integration.unregisterLeaveSubscription(raw);
}
toggleWideControls(false);
}
}, lifetime);
void Panel::trackControl(Ui::RpWidget *widget, rpl::lifetime &lifetime) {
if (!widget) {
return;
}
widget->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) {
if (e->type() == QEvent::Enter) {
trackControlOver(widget, true);
} else if (e->type() == QEvent::Leave) {
trackControlOver(widget, false);
}
}, lifetime);
}
void Panel::trackControlOver(not_null<Ui::RpWidget*> control, bool over) {
if (_niceTooltip) {
_niceTooltip.release()->toggleAnimated(false);
}
if (over) {
Ui::Integration::Instance().registerLeaveSubscription(control);
showNiceTooltip(control);
} else {
Ui::Integration::Instance().unregisterLeaveSubscription(control);
}
toggleWideControls(over);
}
void Panel::showNiceTooltip(not_null<Ui::RpWidget*> control) {
auto text = [&]() -> rpl::producer<QString> {
if (control == _screenShare.data()) {
if (_call->mutedByAdmin()) {
return nullptr;
}
return tr::lng_group_call_tooltip_screen();
} else if (control == _video.data()) {
if (_call->mutedByAdmin()) {
return nullptr;
}
return _call->isSharingCameraValue(
) | rpl::map([=](bool sharing) {
return sharing
? tr::lng_group_call_tooltip_camera_off()
: tr::lng_group_call_tooltip_camera();
}) | rpl::flatten_latest();
} else if (control == _settings.data()) {
return tr::lng_group_call_settings();
} else if (control == _mute->outer()) {
return MuteButtonTooltip(_call);
} else if (control == _hangup.data()) {
return tr::lng_group_call_leave();
}
return rpl::producer<QString>();
}();
if (!text
|| _wideControlsAnimation.animating()
|| !_wideControlsShown) {
return;
}
_niceTooltip.create(
widget().get(),
object_ptr<Ui::FlatLabel>(
widget().get(),
std::move(text),
st::groupCallNiceTooltipLabel),
st::groupCallNiceTooltip);
const auto tooltip = _niceTooltip.data();
const auto weak = QPointer<QWidget>(tooltip);
const auto destroy = [=] {
delete weak.data();
};
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();
const auto countPosition = [=](QSize size) {
const auto strong = weak.data();
if (!strong) {
return QPoint();
}
const auto top = geometry.y()
- st::groupCallNiceTooltipTop
- size.height();
const auto middle = geometry.center().x();
const auto back = _controlsBackgroundWide.data();
if (size.width() >= _viewport->widget()->width()) {
return QPoint(_viewport->widget()->x(), top);
} else if (back && size.width() >= back->width()) {
return QPoint(
back->x() - (size.width() - back->width()) / 2,
top);
} else if (back && (middle - back->x() < size.width() / 2)) {
return QPoint(back->x(), top);
} else if (back
&& (back->x() + back->width() - middle < size.width() / 2)) {
return QPoint(back->x() + back->width() - size.width(), top);
} else {
return QPoint(middle - size.width() / 2, top);
}
};
tooltip->pointAt(geometry, RectPart::Top, countPosition);
tooltip->toggleAnimated(true);
}
void Panel::trackControls(bool track) {
@ -2032,7 +2113,7 @@ void Panel::trackControls(bool track) {
const auto trackOne = [=](auto &&widget) {
trackControl(widget, _trackControlsOverStateLifetime);
};
trackOne(_mute);
trackOne(_mute->outer());
trackOne(_video);
trackOne(_screenShare);
trackOne(_wideMenu);
@ -2106,13 +2187,13 @@ void Panel::updateButtonsGeometry() {
const auto skip = st::groupCallButtonSkipSmall;
const auto fullWidth = (_video->width() + skip)
+ (_screenShare->width() + skip)
+ muteSize
+ (muteSize + skip)
+ (_settings ->width() + skip)
+ _hangup->width() + skip;
+ _hangup->width();
const auto membersSkip = st::groupCallNarrowSkip;
const auto membersWidth = st::groupCallNarrowMembersWidth
+ 2 * membersSkip;
auto left = (widget()->width()
auto left = membersSkip + (widget()->width()
- membersWidth
- membersSkip
- fullWidth) / 2;

View file

@ -26,6 +26,7 @@ class GroupCall;
namespace Ui {
class AbstractButton;
class ImportantTooltip;
class DropdownMenu;
class CallButton;
class CallMuteButton;
@ -102,8 +103,9 @@ private:
void enlargeVideo();
void minimizeVideo();
template <typename WidgetPointer>
void trackControl(WidgetPointer &widget, rpl::lifetime &lifetime);
void trackControl(Ui::RpWidget *widget, rpl::lifetime &lifetime);
void trackControlOver(not_null<Ui::RpWidget*> control, bool over);
void showNiceTooltip(not_null<Ui::RpWidget*> control);
bool updateMode();
void updateControlsGeometry();
@ -191,6 +193,7 @@ private:
object_ptr<Ui::CallButton> _screenShare = { nullptr };
std::unique_ptr<Ui::CallMuteButton> _mute;
object_ptr<Ui::CallButton> _hangup;
object_ptr<Ui::ImportantTooltip> _niceTooltip = { nullptr };
Fn<void()> _callShareLinkCallback;
rpl::lifetime _peerLifetime;

View file

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/gl/gl_surface.h"
#include "ui/effects/animations.h"
#include "ui/effects/cross_line.h"
#include "data/data_group_call.h" // MuteButtonTooltip.
#include "lang/lang_keys.h"
#include "styles/style_calls.h"
@ -603,4 +604,51 @@ QImage GenerateShadow(
return result;
}
rpl::producer<QString> MuteButtonTooltip(not_null<GroupCall*> call) {
//return rpl::single(std::make_tuple(
// (Data::GroupCall*)nullptr,
// call->scheduleDate()
//)) | rpl::then(call->real(
//) | rpl::map([](not_null<Data::GroupCall*> real) {
// using namespace rpl::mappers;
// return real->scheduleDateValue(
// ) | rpl::map([=](TimeId scheduleDate) {
// return std::make_tuple(real.get(), scheduleDate);
// });
//}) | rpl::flatten_latest(
//)) | rpl::map([=](
// Data::GroupCall *real,
// TimeId scheduleDate) -> rpl::producer<QString> {
// if (scheduleDate) {
// return rpl::combine(
// call->canManageValue(),
// (real
// ? real->scheduleStartSubscribedValue()
// : rpl::single(false))
// ) | rpl::map([](bool canManage, bool subscribed) {
// return canManage
// ? tr::lng_group_call_start_now()
// : subscribed
// ? tr::lng_group_call_cancel_reminder()
// : tr::lng_group_call_set_reminder();
// }) | rpl::flatten_latest();
// }
return call->mutedValue(
) | rpl::map([](MuteState muted) {
switch (muted) {
case MuteState::Active:
case MuteState::PushToTalk:
return tr::lng_group_call_you_are_live();
case MuteState::ForceMuted:
return tr::lng_group_call_tooltip_force_muted();
case MuteState::RaisedHand:
return tr::lng_group_call_tooltip_raised_hand();
case MuteState::Muted:
return tr::lng_group_call_tooltip_microphone();
}
Unexpected("Value in MuteState in showNiceTooltip.");
}) | rpl::flatten_latest();
//}) | rpl::flatten_latest();
}
} // namespace Calls::Group

View file

@ -23,6 +23,7 @@ struct ChosenRenderer;
} // namespace Ui
namespace Calls {
class GroupCall;
struct VideoEndpoint;
struct VideoPinToggle;
struct VideoQualityRequest;
@ -158,4 +159,7 @@ private:
int bottomAlpha,
QColor color = QColor(0, 0, 0));
[[nodiscard]] rpl::producer<QString> MuteButtonTooltip(
not_null<GroupCall*> call);
} // namespace Calls::Group

View file

@ -1068,10 +1068,6 @@ rpl::producer<Qt::MouseButton> CallMuteButton::clicks() {
});
}
rpl::producer<not_null<QEvent*>> CallMuteButton::events() const {
return _content->events();
}
QSize CallMuteButton::innerSize() const {
return innerGeometry().size();
}
@ -1169,7 +1165,7 @@ rpl::producer<CallButtonColors> CallMuteButton::colorOverrides() const {
return _colorOverrides.events();
}
not_null<QWidget*> CallMuteButton::outer() const {
not_null<RpWidget*> CallMuteButton::outer() const {
return _content.get();
}

View file

@ -64,7 +64,6 @@ public:
void setStyle(const style::CallMuteButton &st);
void setLevel(float level);
[[nodiscard]] rpl::producer<Qt::MouseButton> clicks();
[[nodiscard]] rpl::producer<not_null<QEvent*>> events() const;
[[nodiscard]] QSize innerSize() const;
[[nodiscard]] QRect innerGeometry() const;
@ -83,7 +82,7 @@ public:
void raise();
void lower();
[[nodiscard]] not_null<QWidget*> outer() const;
[[nodiscard]] not_null<RpWidget*> outer() const;
[[nodiscard]] rpl::producer<CallButtonColors> colorOverrides() const;
[[nodiscard]] rpl::lifetime &lifetime();

@ -1 +1 @@
Subproject commit 11cd08b14206a2ce3669cebafb6e693a30ef14ab
Subproject commit 19543aaf43d97e254f9b379cc3bc77491009f9d4

View file

@ -91,6 +91,8 @@ PRIVATE
# iOS / macOS
platform/darwin/DarwinInterface.h
platform/darwin/DarwinInterface.mm
platform/darwin/DarwinVideoSource.h
platform/darwin/DarwinVideoSource.mm
platform/darwin/DesktopCaptureSourceView.h
platform/darwin/DesktopCaptureSourceView.mm
platform/darwin/DesktopSharingCapturer.h

@ -1 +1 @@
Subproject commit 8fbeb7f5032e588dfd134c9fe80e1880f888f12f
Subproject commit f475fe28e47af4408bc96ba63e63f599c02538ca