Nice three-button narrow mode with gradient fading.

This commit is contained in:
John Preston 2021-05-21 17:15:45 +04:00
parent c12a50544e
commit 385b98ff3d
7 changed files with 310 additions and 92 deletions

View file

@ -195,8 +195,8 @@ callMuteButtonLabel: FlatLabel(defaultFlatLabel) {
} }
} }
callMuteButtonActiveInner: IconButton { callMuteButtonActiveInner: IconButton {
width: 136px; width: 112px;
height: 165px; height: 138px;
} }
callMuteButtonSmallActiveInner: IconButton { callMuteButtonSmallActiveInner: IconButton {
width: 68px; width: 68px;
@ -205,7 +205,7 @@ callMuteButtonSmallActiveInner: IconButton {
callMuteButtonActive: CallButton { callMuteButtonActive: CallButton {
button: callMuteButtonActiveInner; button: callMuteButtonActiveInner;
bg: groupCallLive1; bg: groupCallLive1;
bgSize: 100px; bgSize: 77px;
bgPosition: point(18px, 18px); bgPosition: point(18px, 18px);
outerRadius: 18px; outerRadius: 18px;
outerBg: callAnswerBgOuter; outerBg: callAnswerBgOuter;
@ -221,10 +221,10 @@ callMuteButton: CallMuteButton {
sublabel: FlatLabel(defaultFlatLabel) { sublabel: FlatLabel(defaultFlatLabel) {
textFg: groupCallMemberNotJoinedStatus; textFg: groupCallMemberNotJoinedStatus;
} }
labelsSkip: 5px; labelsSkip: 8px;
sublabelSkip: 19px; sublabelSkip: 14px;
lottieSize: size(67px, 67px); lottieSize: size(54px, 54px);
lottieTop: 35px; lottieTop: 31px;
} }
callMuteButtonSmallActive: CallButton(callMuteButtonActive) { callMuteButtonSmallActive: CallButton(callMuteButtonActive) {
button: callMuteButtonSmallActiveInner; button: callMuteButtonSmallActiveInner;
@ -685,7 +685,6 @@ groupCallTitleTop: 8px;
groupCallSubtitleTop: 26px; groupCallSubtitleTop: 26px;
groupCallWideVideoTop: 24px; groupCallWideVideoTop: 24px;
groupCallMembersMargin: margins(16px, 16px, 16px, 28px);
groupCallAddMember: SettingsButton(defaultSettingsButton) { groupCallAddMember: SettingsButton(defaultSettingsButton) {
textFg: groupCallMemberNotJoinedStatus; textFg: groupCallMemberNotJoinedStatus;
textFgOver: groupCallMemberNotJoinedStatus; textFgOver: groupCallMemberNotJoinedStatus;
@ -780,6 +779,10 @@ groupCallSettingsInner: IconButton(callButton) {
groupCallShareInner: IconButton(groupCallSettingsInner) { groupCallShareInner: IconButton(groupCallSettingsInner) {
icon: icon {{ "calls/group_calls_share", groupCallIconFg }}; icon: icon {{ "calls/group_calls_share", groupCallIconFg }};
} }
groupCallVideoInner: IconButton(groupCallSettingsInner) {
icon: icon {{ "calls/call_camera_muted", groupCallIconFg }};
iconPosition: point(-1px, 16px);
}
groupCallHangupInner: IconButton(callButton) { groupCallHangupInner: IconButton(callButton) {
icon: icon {{ "calls/call_discard", groupCallIconFg }}; icon: icon {{ "calls/call_discard", groupCallIconFg }};
ripple: RippleAnimation(defaultRippleAnimation) { ripple: RippleAnimation(defaultRippleAnimation) {
@ -792,6 +795,15 @@ groupCallSettings: CallButton(callMicrophoneMute) {
groupCallShare: CallButton(groupCallSettings) { groupCallShare: CallButton(groupCallSettings) {
button: groupCallShareInner; button: groupCallShareInner;
} }
groupCallVideo: CallButton(groupCallSettings) {
button: groupCallVideoInner;
}
groupCallVideoInnerActive: IconButton(groupCallVideoInner) {
icon: icon {{ "calls/call_camera_active", groupCallIconFg }};
}
groupCallVideoActive: CallButton(groupCallVideo) {
button: groupCallVideoInnerActive;
}
groupCallHangup: CallButton(callHangup) { groupCallHangup: CallButton(callHangup) {
button: groupCallHangupInner; button: groupCallHangupInner;
bg: groupCallLeaveBg; bg: groupCallLeaveBg;
@ -813,17 +825,14 @@ groupCallHangupSmall: CallButton(groupCallHangup) {
height: 76px; height: 76px;
} }
} }
groupCallVideoSmallInner: IconButton(groupCallSettingsInner) {
icon: icon {{ "calls/call_camera_muted", groupCallIconFg }};
iconPosition: point(-1px, 16px);
height: 76px;
}
groupCallVideoSmall: CallButton(groupCallShareSmall) { groupCallVideoSmall: CallButton(groupCallShareSmall) {
button: groupCallVideoSmallInner; button: IconButton(groupCallVideoInner) {
height: 76px;
}
} }
groupCallVideoActiveSmall: CallButton(groupCallVideoSmall) { groupCallVideoActiveSmall: CallButton(groupCallVideoSmall) {
button: IconButton(groupCallVideoSmallInner) { button: IconButton(groupCallVideoInnerActive) {
icon: icon {{ "calls/call_camera_active", groupCallIconFg }}; height: 76px;
} }
} }
groupCallScreenShareSmall: CallButton(groupCallShareSmall) { groupCallScreenShareSmall: CallButton(groupCallShareSmall) {
@ -832,15 +841,20 @@ groupCallScreenShareSmall: CallButton(groupCallShareSmall) {
height: 76px; height: 76px;
} }
} }
groupCallButtonSkip: 43px; groupCallButtonSkip: 40px;
groupCallButtonSkipSmall: 4px; groupCallButtonSkipSmall: 4px;
groupCallButtonBottomSkip: 145px; groupCallButtonBottomSkip: 113px;
groupCallButtonBottomSkipSmall: 95px; groupCallButtonBottomSkipSmall: 95px;
groupCallButtonBottomSkipWide: 122px; groupCallButtonBottomSkipWide: 122px;
groupCallMembersBottomSkipSmall: 72px;
groupCallControlsBackMargin: margins(2px, 2px, 2px, 2px); groupCallControlsBackMargin: margins(2px, 2px, 2px, 2px);
groupCallControlsBackRadius: 12px; groupCallControlsBackRadius: 12px;
groupCallMuteBottomSkip: 160px; groupCallMuteBottomSkip: 116px;
groupCallMembersMargin: margins(16px, 16px, 16px, 60px);
groupCallMembersBottomSkip: 80px;
groupCallMembersShadowHeight: 160px;
groupCallMembersFadeSkip: 10px;
groupCallMembersFadeHeight: 100px;
groupCallTopBarUserpics: GroupCallUserpics { groupCallTopBarUserpics: GroupCallUserpics {
size: 28px; size: 28px;

View file

@ -438,16 +438,27 @@ void LargeVideo::paintControls(Painter &p, QRect clip) {
_track.row->name().drawLeftElided(p, nameLeft, nameTop, hasWidth, width); _track.row->name().drawLeftElided(p, nameLeft, nameTop, hasWidth, width);
} }
QImage GenerateShadow(int height, int topAlpha, int bottomAlpha) { QImage GenerateShadow(
int height,
int topAlpha,
int bottomAlpha,
QColor color) {
Expects(topAlpha >= 0 && topAlpha < 256); Expects(topAlpha >= 0 && topAlpha < 256);
Expects(bottomAlpha >= 0 && bottomAlpha < 256); Expects(bottomAlpha >= 0 && bottomAlpha < 256);
Expects(height * style::DevicePixelRatio() < 65536); Expects(height * style::DevicePixelRatio() < 65536);
const auto base = (uint32(color.red()) << 16)
| (uint32(color.green()) << 8)
| uint32(color.blue());
const auto premultiplied = (topAlpha == bottomAlpha) || !base;
auto result = QImage( auto result = QImage(
QSize(1, height * style::DevicePixelRatio()), QSize(1, height * style::DevicePixelRatio()),
QImage::Format_ARGB32_Premultiplied); (premultiplied
? QImage::Format_ARGB32_Premultiplied
: QImage::Format_ARGB32));
if (topAlpha == bottomAlpha) { if (topAlpha == bottomAlpha) {
result.fill(QColor(0, 0, 0, topAlpha)); color.setAlpha(topAlpha);
result.fill(color);
return result; return result;
} }
constexpr auto kShift = 16; constexpr auto kShift = 16;
@ -460,13 +471,17 @@ QImage GenerateShadow(int height, int topAlpha, int bottomAlpha) {
auto ints = reinterpret_cast<uint32*>(result.bits()); auto ints = reinterpret_cast<uint32*>(result.bits());
if (topAlpha < bottomAlpha) { if (topAlpha < bottomAlpha) {
for (auto i = uint32(0); i != till; i += step) { for (auto i = uint32(0); i != till; i += step) {
*ints++ = ((topAlpha + (i >> kShift)) << 24); *ints++ = base | ((topAlpha + (i >> kShift)) << 24);
} }
} else { } else {
for (auto i = uint32(0); i != till; i += step) { for (auto i = uint32(0); i != till; i += step) {
*ints++ = ((topAlpha - (i >> kShift)) << 24); *ints++ = base | ((topAlpha - (i >> kShift)) << 24);
} }
} }
if (!premultiplied) {
result = std::move(result).convertToFormat(
QImage::Format_ARGB32_Premultiplied);
}
return result; return result;
} }

View file

@ -114,6 +114,7 @@ private:
[[nodiscard]] QImage GenerateShadow( [[nodiscard]] QImage GenerateShadow(
int height, int height,
int topAlpha, int topAlpha,
int bottomAlpha); int bottomAlpha,
QColor color = QColor(0, 0, 0));
} // namespace Calls::Group } // namespace Calls::Group

View file

@ -1677,9 +1677,6 @@ auto Members::kickParticipantRequests() const
} }
int Members::desiredHeight() const { int Members::desiredHeight() const {
const auto addMember = _addMemberButton.current();
const auto top = _pinnedVideoWrap->height()
+ (addMember ? addMember->height() : 0);
const auto count = [&] { const auto count = [&] {
if (const auto real = _call->lookupReal()) { if (const auto real = _call->lookupReal()) {
return real->fullCount(); return real->fullCount();
@ -1690,16 +1687,18 @@ int Members::desiredHeight() const {
const auto single = /*(_mode.current() == PanelMode::Wide) const auto single = /*(_mode.current() == PanelMode::Wide)
? (st::groupCallNarrowSize.height() + st::groupCallNarrowRowSkip * 2) ? (st::groupCallNarrowSize.height() + st::groupCallNarrowRowSkip * 2)
: */st::groupCallMembersList.item.height; : */st::groupCallMembersList.item.height;
return top const auto desired = (_layout->height() - _list->height())
+ (use * single) + (use * single)
+ (use ? st::lineWidth : 0); + (use ? st::lineWidth : 0);
return std::max(height(), desired);
} }
rpl::producer<int> Members::desiredHeightValue() const { rpl::producer<int> Members::desiredHeightValue() const {
return rpl::combine( return rpl::combine(
heightValue(), heightValue(),
_addMemberButton.value(), _addMemberButton.value(),
_listController->fullCountValue() _listController->fullCountValue(),
_mode.value()
) | rpl::map([=] { ) | rpl::map([=] {
return desiredHeight(); return desiredHeight();
}); });
@ -1810,6 +1809,16 @@ void Members::setMode(PanelMode mode) {
// : PeerListContent::Mode::Default); // : PeerListContent::Mode::Default);
} }
QRect Members::getInnerGeometry() const {
const auto addMembers = _addMemberButton.current();
const auto add = addMembers ? addMembers->height() : 0;
return QRect(
0,
-_scroll->scrollTop(),
width(),
_list->y() + _list->height());
}
rpl::producer<int> Members::fullCountValue() const { rpl::producer<int> Members::fullCountValue() const {
return _listController->fullCountValue(); return _listController->fullCountValue();
} }
@ -1817,10 +1826,19 @@ rpl::producer<int> Members::fullCountValue() const {
void Members::setupList() { void Members::setupList() {
_listController->setStyleOverrides(&st::groupCallMembersList); _listController->setStyleOverrides(&st::groupCallMembersList);
_list = _layout->add(object_ptr<ListWidget>( _list = _layout->add(object_ptr<ListWidget>(
this, _layout.get(),
_listController.get())); _listController.get()));
const auto skip = _layout->add(object_ptr<Ui::RpWidget>(_layout.get()));
_mode.value(
) | rpl::start_with_next([=](PanelMode mode) {
skip->resize(skip->width(), (mode == PanelMode::Default)
? st::groupCallMembersBottomSkip
: 0);
}, skip->lifetime());
_layout->heightValue( rpl::combine(
_mode.value(),
_layout->heightValue()
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
resizeToList(); resizeToList();
}, _layout->lifetime()); }, _layout->lifetime());
@ -2030,7 +2048,7 @@ void Members::setupFakeRoundCorners() {
}; };
const auto create = [&](QPoint imagePartOrigin) { const auto create = [&](QPoint imagePartOrigin) {
const auto result = Ui::CreateChild<Ui::RpWidget>(this); const auto result = Ui::CreateChild<Ui::RpWidget>(_layout.get());
result->show(); result->show();
result->resize(size, size); result->resize(size, size);
result->setAttribute(Qt::WA_TransparentForMouseEvents); result->setAttribute(Qt::WA_TransparentForMouseEvents);
@ -2050,14 +2068,24 @@ void Members::setupFakeRoundCorners() {
const auto bottomleft = create({ 0, shift }); const auto bottomleft = create({ 0, shift });
const auto bottomright = create({ shift, shift }); const auto bottomright = create({ shift, shift });
sizeValue( rpl::combine(
) | rpl::start_with_next([=](QSize size) { _list->geometryValue(),
topleft->move(0, 0); _addMemberButton.value() | rpl::map([=](Ui::RpWidget *widget) {
topright->move(size.width() - topright->width(), 0); topleft->raise();
bottomleft->move(0, size.height() - bottomleft->height()); topright->raise();
bottomright->move( bottomleft->raise();
size.width() - bottomright->width(), bottomright->raise();
size.height() - bottomright->height()); return widget ? widget->heightValue() : rpl::single(0);
}) | rpl::flatten_latest()
) | rpl::start_with_next([=](QRect list, int addMembers) {
const auto left = list.x();
const auto top = list.y() - addMembers;
const auto right = list.x() + list.width() - topright->width();
const auto bottom = list.y() + list.height() - bottomleft->height();
topleft->move(left, top);
topright->move(right, top);
bottomleft->move(left, bottom);
bottomright->move(right, bottom);
}, lifetime()); }, lifetime());
refreshImage(); refreshImage();

View file

@ -58,6 +58,7 @@ public:
[[nodiscard]] MembersRow *lookupRow(not_null<PeerData*> peer) const; [[nodiscard]] MembersRow *lookupRow(not_null<PeerData*> peer) const;
void setMode(PanelMode mode); void setMode(PanelMode mode);
[[nodiscard]] QRect getInnerGeometry() const;
private: private:
class Controller; class Controller;

View file

@ -384,6 +384,16 @@ struct Panel::VideoTile {
VideoEndpoint endpoint; VideoEndpoint endpoint;
}; };
struct Panel::ControlsBackgroundNarrow {
explicit ControlsBackgroundNarrow(not_null<QWidget*> parent)
: shadow(parent)
, blocker(parent) {
}
Ui::RpWidget shadow;
Ui::RpWidget blocker;
};
Panel::Panel(not_null<GroupCall*> call) Panel::Panel(not_null<GroupCall*> call)
: _call(call) : _call(call)
, _peer(call->peer()) , _peer(call->peer())
@ -697,6 +707,8 @@ void Panel::initControls() {
) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) { ) | rpl::start_with_next([=](not_null<Data::GroupCall*> real) {
setupRealMuteButtonState(real); setupRealMuteButtonState(real);
}, _callLifetime); }, _callLifetime);
refreshControlsBackground();
} }
void Panel::refreshLeftButton() { void Panel::refreshLeftButton() {
@ -799,7 +811,7 @@ void Panel::setupRealMuteButtonState(not_null<Data::GroupCall*> real) {
real->scheduleDateValue(), real->scheduleDateValue(),
real->scheduleStartSubscribedValue(), real->scheduleStartSubscribedValue(),
Data::CanManageGroupCallValue(_peer), Data::CanManageGroupCallValue(_peer),
_videoMode.value() _mode.value()
) | rpl::distinct_until_changed( ) | rpl::distinct_until_changed(
) | rpl::filter( ) | rpl::filter(
_2 != GroupCall::InstanceState::TransitionToRtc _2 != GroupCall::InstanceState::TransitionToRtc
@ -809,7 +821,8 @@ void Panel::setupRealMuteButtonState(not_null<Data::GroupCall*> real) {
TimeId scheduleDate, TimeId scheduleDate,
bool scheduleStartSubscribed, bool scheduleStartSubscribed,
bool canManage, bool canManage,
bool videoMode) { PanelMode mode) {
const auto wide = (mode == PanelMode::Wide);
using Type = Ui::CallMuteButtonType; using Type = Ui::CallMuteButtonType;
_mute->setState(Ui::CallMuteButtonState{ _mute->setState(Ui::CallMuteButtonState{
.text = (scheduleDate .text = (scheduleDate
@ -821,19 +834,19 @@ void Panel::setupRealMuteButtonState(not_null<Data::GroupCall*> real) {
: state == GroupCall::InstanceState::Disconnected : state == GroupCall::InstanceState::Disconnected
? tr::lng_group_call_connecting(tr::now) ? tr::lng_group_call_connecting(tr::now)
: mute == MuteState::ForceMuted : mute == MuteState::ForceMuted
? (videoMode ? (wide
? tr::lng_group_call_force_muted_small(tr::now) ? tr::lng_group_call_force_muted_small(tr::now)
: tr::lng_group_call_force_muted(tr::now)) : tr::lng_group_call_force_muted(tr::now))
: mute == MuteState::RaisedHand : mute == MuteState::RaisedHand
? (videoMode ? (wide
? tr::lng_group_call_raised_hand_small(tr::now) ? tr::lng_group_call_raised_hand_small(tr::now)
: tr::lng_group_call_raised_hand(tr::now)) : tr::lng_group_call_raised_hand(tr::now))
: mute == MuteState::Muted : mute == MuteState::Muted
? tr::lng_group_call_unmute(tr::now) ? tr::lng_group_call_unmute(tr::now)
: (videoMode : (wide
? tr::lng_group_call_you_are_live_small(tr::now) ? tr::lng_group_call_you_are_live_small(tr::now)
: tr::lng_group_call_you_are_live(tr::now))), : tr::lng_group_call_you_are_live(tr::now))),
.subtext = ((scheduleDate || videoMode) .subtext = ((scheduleDate || wide)
? QString() ? QString()
: state == GroupCall::InstanceState::Disconnected : state == GroupCall::InstanceState::Disconnected
? QString() ? QString()
@ -930,6 +943,10 @@ void Panel::setupScheduledLabels(rpl::producer<TimeId> date) {
}, _startsWhen->lifetime()); }, _startsWhen->lifetime());
} }
PanelMode Panel::mode() const {
return _mode.current();
}
void Panel::setupMembers() { void Panel::setupMembers() {
if (_members) { if (_members) {
return; return;
@ -942,7 +959,7 @@ void Panel::setupMembers() {
_members.create(widget(), _call); _members.create(widget(), _call);
setupPinnedVideo(); setupPinnedVideo();
_members->setMode(_mode); _members->setMode(mode());
_members->show(); _members->show();
_members->desiredHeightValue( _members->desiredHeightValue(
@ -985,7 +1002,7 @@ void Panel::setupMembers() {
_call->videoEndpointPinnedValue( _call->videoEndpointPinnedValue(
) | rpl::start_with_next([=](const VideoEndpoint &pinned) { ) | rpl::start_with_next([=](const VideoEndpoint &pinned) {
if (_mode == PanelMode::Wide) { if (mode() == PanelMode::Wide) {
refreshTilesGeometry(); refreshTilesGeometry();
} else if (pinned) { } else if (pinned) {
enlargeVideo(); enlargeVideo();
@ -1062,8 +1079,12 @@ void Panel::minimizeVideo() {
} }
void Panel::raiseControls() { void Panel::raiseControls() {
if (_controlsBackground) { if (_controlsBackgroundWide) {
_controlsBackground->raise(); _controlsBackgroundWide->raise();
}
if (_controlsBackgroundNarrow) {
_controlsBackgroundNarrow->shadow.raise();
_controlsBackgroundNarrow->blocker.raise();
} }
const auto buttons = { const auto buttons = {
&_settings, &_settings,
@ -1084,7 +1105,7 @@ void Panel::refreshTilesGeometry() {
const auto outer = _pinnedVideoWrap->size(); const auto outer = _pinnedVideoWrap->size();
if (_videoTiles.empty() if (_videoTiles.empty()
|| outer.isEmpty() || outer.isEmpty()
|| _mode == PanelMode::Default) { || mode() == PanelMode::Default) {
return; return;
} }
struct Geometry { struct Geometry {
@ -1204,7 +1225,7 @@ void Panel::setupPinnedVideo() {
auto video = std::make_unique<LargeVideo>( auto video = std::make_unique<LargeVideo>(
raw, raw,
st::groupCallLargeVideoWide, st::groupCallLargeVideoWide,
(_mode == PanelMode::Wide), (mode() == PanelMode::Wide),
rpl::single(LargeVideoTrack{ track.track.get(), row }), rpl::single(LargeVideoTrack{ track.track.get(), row }),
_call->videoEndpointPinnedValue() | rpl::map(_1 == endpoint)); _call->videoEndpointPinnedValue() | rpl::map(_1 == endpoint));
@ -1781,7 +1802,7 @@ bool Panel::updateMode() {
const auto wide = _call->videoCall() const auto wide = _call->videoCall()
&& (widget()->width() >= st::groupCallWideModeWidthMin); && (widget()->width() >= st::groupCallWideModeWidthMin);
const auto mode = wide ? PanelMode::Wide : PanelMode::Default; const auto mode = wide ? PanelMode::Wide : PanelMode::Default;
if (_mode == mode) { if (_mode.current() == mode) {
return false; return false;
} }
_mode = mode; _mode = mode;
@ -1813,15 +1834,120 @@ bool Panel::updateMode() {
} }
void Panel::refreshControlsBackground() { void Panel::refreshControlsBackground() {
if (_mode != PanelMode::Wide) { if (mode() == PanelMode::Default) {
trackControls(false); trackControls(false);
_controlsBackground.destroy(); _controlsBackgroundWide.destroy();
} else if (_controlsBackground) { if (_controlsBackgroundNarrow) {
return; return;
}
setupControlsBackgroundNarrow();
} else {
_controlsBackgroundNarrow = nullptr;
if (_controlsBackgroundWide) {
return;
}
setupControlsBackgroundWide();
} }
_controlsBackground.create(widget()); raiseControls();
_controlsBackground->show(); updateButtonsGeometry();
auto &lifetime = _controlsBackground->lifetime(); }
void Panel::setupControlsBackgroundNarrow() {
_controlsBackgroundNarrow = std::make_unique<ControlsBackgroundNarrow>(
widget());
_controlsBackgroundNarrow->shadow.show();
_controlsBackgroundNarrow->blocker.show();
auto &lifetime = _controlsBackgroundNarrow->shadow.lifetime();
const auto factor = cIntRetinaFactor();
const auto height = std::max(
st::groupCallMembersShadowHeight,
st::groupCallMembersFadeSkip + st::groupCallMembersFadeHeight);
const auto full = lifetime.make_state<QImage>(
QSize(1, height * factor),
QImage::Format_ARGB32_Premultiplied);
rpl::single(
rpl::empty_value()
) | rpl::then(
style::PaletteChanged()
) | rpl::start_with_next([=] {
full->fill(Qt::transparent);
auto p = QPainter(full);
const auto bottom = (height - st::groupCallMembersFadeSkip) * factor;
p.fillRect(
0,
bottom,
full->width(),
st::groupCallMembersFadeSkip * factor,
st::groupCallMembersBg);
p.drawImage(
QRect(
0,
bottom - (st::groupCallMembersFadeHeight * factor),
full->width(),
st::groupCallMembersFadeHeight * factor),
GenerateShadow(
st::groupCallMembersFadeHeight,
0,
255,
st::groupCallMembersBg->c));
p.drawImage(
QRect(
0,
(height - st::groupCallMembersShadowHeight) * factor,
full->width(),
st::groupCallMembersShadowHeight * factor),
GenerateShadow(
st::groupCallMembersShadowHeight,
0,
255,
st::groupCallBg->c));
}, lifetime);
_controlsBackgroundNarrow->shadow.resize(
(widget()->width()
- st::groupCallMembersMargin.left()
- st::groupCallMembersMargin.right()),
height);
_controlsBackgroundNarrow->shadow.paintRequest(
) | rpl::start_with_next([=](QRect clip) {
auto p = QPainter(&_controlsBackgroundNarrow->shadow);
clip = clip.intersected(_controlsBackgroundNarrow->shadow.rect());
const auto inner = _members->getInnerGeometry().translated(
_members->x() - _controlsBackgroundNarrow->shadow.x(),
_members->y() - _controlsBackgroundNarrow->shadow.y());
const auto faded = clip.intersected(inner);
if (!faded.isEmpty()) {
const auto factor = cIntRetinaFactor();
p.drawImage(
faded,
*full,
QRect(
0,
faded.y() * factor,
full->width(),
faded.height() * factor));
}
const auto bottom = inner.y() + inner.height();
const auto after = clip.intersected(QRect(
0,
bottom,
inner.width(),
_controlsBackgroundNarrow->shadow.height() - bottom));
if (!after.isEmpty()) {
p.fillRect(after, st::groupCallBg);
}
}, lifetime);
_controlsBackgroundNarrow->shadow.setAttribute(
Qt::WA_TransparentForMouseEvents);
_controlsBackgroundNarrow->blocker.setUpdatesEnabled(false);
}
void Panel::setupControlsBackgroundWide() {
_controlsBackgroundWide.create(widget());
_controlsBackgroundWide->show();
auto &lifetime = _controlsBackgroundWide->lifetime();
const auto color = lifetime.make_state<style::complex_color>([] { const auto color = lifetime.make_state<style::complex_color>([] {
auto result = st::groupCallBg->c; auto result = st::groupCallBg->c;
result.setAlphaF(kControlsBackgroundOpacity); result.setAlphaF(kControlsBackgroundOpacity);
@ -1830,14 +1956,13 @@ void Panel::refreshControlsBackground() {
const auto corners = lifetime.make_state<Ui::RoundRect>( const auto corners = lifetime.make_state<Ui::RoundRect>(
st::groupCallControlsBackRadius, st::groupCallControlsBackRadius,
color->color()); color->color());
_controlsBackground->paintRequest( _controlsBackgroundWide->paintRequest(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
auto p = QPainter(_controlsBackground.data()); auto p = QPainter(_controlsBackgroundWide.data());
corners->paint(p, _controlsBackground->rect()); corners->paint(p, _controlsBackgroundWide->rect());
}, lifetime); }, lifetime);
trackControls(true); trackControls(true);
raiseControls();
} }
void Panel::trackControls(bool track) { void Panel::trackControls(bool track) {
@ -1875,7 +2000,7 @@ void Panel::trackControls(bool track) {
trackOne(_settings); trackOne(_settings);
trackOne(_callShare); trackOne(_callShare);
trackOne(_hangup); trackOne(_hangup);
trackOne(_controlsBackground); trackOne(_controlsBackgroundWide);
} }
void Panel::updateControlsGeometry() { void Panel::updateControlsGeometry() {
@ -1923,23 +2048,20 @@ void Panel::updateButtonsGeometry() {
toggleOne(_callShare); toggleOne(_callShare);
toggleOne(_hangup); toggleOne(_hangup);
}; };
if (_videoMode.current()) { if (mode() == PanelMode::Wide) {
_mute->setStyle(st::callMuteButtonSmall); _mute->setStyle(st::callMuteButtonSmall);
const auto shown = _wideControlsAnimation.value( const auto shown = _wideControlsAnimation.value(
_wideControlsShown ? 1. : 0.); _wideControlsShown ? 1. : 0.);
toggle(_mode != PanelMode::Wide || shown > 0.); toggle(shown > 0.);
for (const auto &tile : _videoTiles) { for (const auto &tile : _videoTiles) {
tile.video->setControlsShown(shown); tile.video->setControlsShown(shown);
} }
const auto buttonsTop = widget()->height() const auto buttonsTop = widget()->height() - anim::interpolate(
- (_mode == PanelMode::Wide 0,
? anim::interpolate( st::groupCallButtonBottomSkipWide,
0, shown);
st::groupCallButtonBottomSkipWide,
shown)
: st::groupCallButtonBottomSkipSmall);
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 = (_video ? 1 : 2) * st::groupCallButtonSkipSmall; const auto skip = (_video ? 1 : 2) * st::groupCallButtonSkipSmall;
@ -1951,28 +2073,32 @@ void Panel::updateButtonsGeometry() {
const auto membersSkip = st::groupCallNarrowSkip; const auto membersSkip = st::groupCallNarrowSkip;
const auto membersWidth = st::groupCallNarrowMembersWidth const auto membersWidth = st::groupCallNarrowMembersWidth
+ 2 * membersSkip; + 2 * membersSkip;
auto left = (_mode == PanelMode::Default) auto left = (widget()->width()
? (widget()->width() - fullWidth) / 2 - membersWidth
: ((widget()->width() - membersSkip
- membersWidth - fullWidth) / 2;
- membersSkip
- fullWidth) / 2);
_mute->moveInner({ left + addSkip, buttonsTop + addSkip }); _mute->moveInner({ left + addSkip, buttonsTop + addSkip });
left += muteSize + skip; left += muteSize + skip;
if (_video) { if (_video) {
_video->setStyle(
st::groupCallVideoSmall,
&st::groupCallVideoActiveSmall);
_video->moveToLeft(left, buttonsTop); _video->moveToLeft(left, buttonsTop);
left += _video->width() + skip; left += _video->width() + skip;
} }
if (_screenShare) { if (_screenShare) {
_screenShare->setVisible(true);
_screenShare->moveToLeft(left, buttonsTop); _screenShare->moveToLeft(left, buttonsTop);
left += _video->width() + skip; left += _video->width() + skip;
} }
if (_settings) { if (_settings) {
_settings->setVisible(true);
_settings->setStyle(st::groupCallSettingsSmall); _settings->setStyle(st::groupCallSettingsSmall);
_settings->moveToLeft(left, buttonsTop); _settings->moveToLeft(left, buttonsTop);
left += _settings->width() + skip; left += _settings->width() + skip;
} }
if (_callShare) { if (_callShare) {
_callShare->setVisible(true);
_callShare->setStyle(st::groupCallShareSmall); _callShare->setStyle(st::groupCallShareSmall);
_callShare->moveToLeft(left, buttonsTop); _callShare->moveToLeft(left, buttonsTop);
left += _callShare->width() + skip; left += _callShare->width() + skip;
@ -1980,13 +2106,13 @@ void Panel::updateButtonsGeometry() {
_hangup->setStyle(st::groupCallHangupSmall); _hangup->setStyle(st::groupCallHangupSmall);
_hangup->moveToLeft(left, buttonsTop); _hangup->moveToLeft(left, buttonsTop);
left += _hangup->width(); left += _hangup->width();
if (_controlsBackground) { if (_controlsBackgroundWide) {
const auto rect = QRect( const auto rect = QRect(
left - fullWidth, left - fullWidth,
buttonsTop, buttonsTop,
fullWidth, fullWidth,
_hangup->height()); _hangup->height());
_controlsBackground->setGeometry( _controlsBackgroundWide->setGeometry(
rect.marginsAdded(st::groupCallControlsBackMargin)); rect.marginsAdded(st::groupCallControlsBackMargin));
} }
} else { } else {
@ -2003,17 +2129,46 @@ void Panel::updateButtonsGeometry() {
+ 2 * st::groupCallButtonSkip; + 2 * st::groupCallButtonSkip;
_mute->moveInner({ (widget()->width() - muteSize) / 2, muteTop }); _mute->moveInner({ (widget()->width() - muteSize) / 2, muteTop });
const auto leftButtonLeft = (widget()->width() - fullWidth) / 2; const auto leftButtonLeft = (widget()->width() - fullWidth) / 2;
if (_screenShare) {
_screenShare->setVisible(false);
}
if (_video) {
_video->setStyle(st::groupCallVideo, &st::groupCallVideoActive);
_video->moveToLeft(leftButtonLeft, buttonsTop);
}
if (_settings) { if (_settings) {
_settings->setVisible(!_video);
_settings->setStyle(st::groupCallSettings); _settings->setStyle(st::groupCallSettings);
_settings->moveToLeft(leftButtonLeft, buttonsTop); _settings->moveToLeft(leftButtonLeft, buttonsTop);
} }
if (_callShare) { if (_callShare) {
_callShare->setVisible(!_video);
_callShare->setStyle(st::groupCallShare); _callShare->setStyle(st::groupCallShare);
_callShare->moveToLeft(leftButtonLeft, buttonsTop); _callShare->moveToLeft(leftButtonLeft, buttonsTop);
} }
_hangup->setStyle(st::groupCallHangup); _hangup->setStyle(st::groupCallHangup);
_hangup->moveToRight(leftButtonLeft, buttonsTop); _hangup->moveToRight(leftButtonLeft, buttonsTop);
} }
if (_controlsBackgroundNarrow) {
const auto left = st::groupCallMembersMargin.left();
const auto width = (widget()->width()
- st::groupCallMembersMargin.left()
- st::groupCallMembersMargin.right());
_controlsBackgroundNarrow->shadow.setGeometry(
left,
(widget()->height()
- st::groupCallMembersMargin.bottom()
- _controlsBackgroundNarrow->shadow.height()),
width,
_controlsBackgroundNarrow->shadow.height());
_controlsBackgroundNarrow->blocker.setGeometry(
left,
(widget()->height()
- st::groupCallMembersMargin.bottom()
- st::groupCallMembersBottomSkip),
width,
st::groupCallMembersBottomSkip);
}
} }
void Panel::updateMembersGeometry() { void Panel::updateMembersGeometry() {
@ -2021,7 +2176,7 @@ void Panel::updateMembersGeometry() {
return; return;
} }
const auto desiredHeight = _members->desiredHeight(); const auto desiredHeight = _members->desiredHeight();
if (_mode == PanelMode::Wide) { if (mode() == PanelMode::Wide) {
const auto skip = st::groupCallNarrowSkip; const auto skip = st::groupCallNarrowSkip;
const auto membersWidth = st::groupCallNarrowMembersWidth; const auto membersWidth = st::groupCallNarrowMembersWidth;
const auto top = st::groupCallWideVideoTop; const auto top = st::groupCallWideVideoTop;
@ -2036,9 +2191,7 @@ void Panel::updateMembersGeometry() {
widget()->width() - membersWidth - 3 * skip, widget()->width() - membersWidth - 3 * skip,
widget()->height() - top - skip); widget()->height() - top - skip);
} else { } else {
const auto membersBottom = _videoMode.current() const auto membersBottom = widget()->height();
? (widget()->height() - st::groupCallMembersBottomSkipSmall)
: (widget()->height() - st::groupCallMuteBottomSkip);
const auto membersTop = st::groupCallMembersTop; const auto membersTop = st::groupCallMembersTop;
const auto availableHeight = membersBottom const auto availableHeight = membersBottom
- st::groupCallMembersMargin.bottom() - st::groupCallMembersMargin.bottom()
@ -2086,7 +2239,7 @@ void Panel::refreshTitle() {
_title->setAttribute(Qt::WA_TransparentForMouseEvents); _title->setAttribute(Qt::WA_TransparentForMouseEvents);
} }
refreshTitleGeometry(); refreshTitleGeometry();
if (!_subtitle && _mode == PanelMode::Default) { if (!_subtitle && mode() == PanelMode::Default) {
_subtitle.create( _subtitle.create(
widget(), widget(),
rpl::single( rpl::single(
@ -2141,7 +2294,7 @@ void Panel::refreshTitleGeometry() {
: fullRect; : fullRect;
const auto best = _title->naturalWidth(); const auto best = _title->naturalWidth();
const auto from = (widget()->width() - best) / 2; const auto from = (widget()->width() - best) / 2;
const auto top = (_mode == PanelMode::Default) const auto top = (mode() == PanelMode::Default)
? st::groupCallTitleTop ? st::groupCallTitleTop
: (st::groupCallWideVideoTop : (st::groupCallWideVideoTop
- st::groupCallTitleLabel.style.font->height) / 2; - st::groupCallTitleLabel.style.font->height) / 2;

View file

@ -71,9 +71,12 @@ public:
private: private:
using State = GroupCall::State; using State = GroupCall::State;
struct VideoTile; struct VideoTile;
struct ControlsBackgroundNarrow;
[[nodiscard]] not_null<Ui::RpWidget*> widget() const; [[nodiscard]] not_null<Ui::RpWidget*> widget() const;
[[nodiscard]] PanelMode mode() const;
void paint(QRect clip); void paint(QRect clip);
void initWindow(); void initWindow();
@ -102,6 +105,8 @@ private:
void updateButtonsGeometry(); void updateButtonsGeometry();
void updateMembersGeometry(); void updateMembersGeometry();
void refreshControlsBackground(); void refreshControlsBackground();
void setupControlsBackgroundWide();
void setupControlsBackgroundNarrow();
void showControls(); void showControls();
void refreshLeftButton(); void refreshLeftButton();
void refreshTilesGeometry(); void refreshTilesGeometry();
@ -134,7 +139,7 @@ private:
const std::unique_ptr<Ui::Window> _window; const std::unique_ptr<Ui::Window> _window;
const std::unique_ptr<Ui::LayerManager> _layerBg; const std::unique_ptr<Ui::LayerManager> _layerBg;
PanelMode _mode = PanelMode(); rpl::variable<PanelMode> _mode;
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
std::unique_ptr<Ui::Platform::TitleControls> _controls; std::unique_ptr<Ui::Platform::TitleControls> _controls;
@ -167,7 +172,8 @@ private:
bool _wideControlsShown = false; bool _wideControlsShown = false;
Ui::Animations::Simple _wideControlsAnimation; Ui::Animations::Simple _wideControlsAnimation;
object_ptr<Ui::RpWidget> _controlsBackground = { nullptr }; object_ptr<Ui::RpWidget> _controlsBackgroundWide = { nullptr };
std::unique_ptr<ControlsBackgroundNarrow> _controlsBackgroundNarrow;
object_ptr<Ui::CallButton> _settings = { nullptr }; object_ptr<Ui::CallButton> _settings = { nullptr };
object_ptr<Ui::CallButton> _callShare = { nullptr }; object_ptr<Ui::CallButton> _callShare = { nullptr };
object_ptr<Ui::CallButton> _video = { nullptr }; object_ptr<Ui::CallButton> _video = { nullptr };