diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 0ad1c75ea..eedd87c6b 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -500,3 +500,8 @@ groupCallMuteBottomSkip: 149px; groupCallTopBarUserpicSize: 28px; groupCallTopBarUserpicShift: 8px; groupCallTopBarUserpicStroke: 2px; +groupCallTopBarJoin: RoundButton(defaultActiveButton) { + width: -30px; + height: 28px; + textTop: 5px; +} diff --git a/Telegram/SourceFiles/calls/calls_top_bar.cpp b/Telegram/SourceFiles/calls/calls_top_bar.cpp index e129b20b5..f0200f503 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.cpp +++ b/Telegram/SourceFiles/calls/calls_top_bar.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/buttons.h" #include "ui/widgets/labels.h" +#include "ui/chat/group_call_bar.h" // Ui::GroupCallBarContent. #include "ui/layers/generic_box.h" #include "ui/wrap/padding_wrap.h" #include "ui/text/format_values.h" @@ -18,7 +19,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "calls/calls_instance.h" #include "calls/calls_signal_bars.h" #include "calls/calls_group_panel.h" // LeaveGroupCallBox. +#include "history/view/history_view_group_call_tracker.h" // ContentByCall. #include "data/data_user.h" +#include "data/data_group_call.h" #include "data/data_channel.h" #include "data/data_changes.h" #include "main/main_session.h" @@ -104,7 +107,12 @@ TopBar::TopBar( : object_ptr(nullptr)) , _fullInfoLabel(this, st::callBarInfoLabel) , _shortInfoLabel(this, st::callBarInfoLabel) -, _hangupLabel(this, st::callBarLabel, tr::lng_call_bar_hangup(tr::now).toUpper()) +, _hangupLabel(_call + ? object_ptr( + this, + st::callBarLabel, + tr::lng_call_bar_hangup(tr::now).toUpper()) + : object_ptr(nullptr)) , _mute(this, st::callBarMuteToggle) , _info(this) , _hangup(this, st::callBarHangup) { @@ -136,8 +144,8 @@ void TopBar::initControls() { update(); }, lifetime()); - if (_groupCall) { - _groupCall->mutedValue( + if (const auto group = _groupCall.get()) { + group->mutedValue( ) | rpl::start_with_next([=](MuteState state) { if (state == MuteState::ForceMuted) { _mute->clearState(); @@ -146,6 +154,8 @@ void TopBar::initControls() { Qt::WA_TransparentForMouseEvents, (state == MuteState::ForceMuted)); }, _mute->lifetime()); + + subscribeToMembersChanges(group); } if (const auto call = _call.get()) { @@ -187,6 +197,33 @@ void TopBar::initControls() { updateDurationText(); } +void TopBar::subscribeToMembersChanges(not_null call) { + const auto channel = call->channel(); + channel->session().changes().peerFlagsValue( + channel, + Data::PeerUpdate::Flag::GroupCall + ) | rpl::map([=] { + return channel->call(); + }) | rpl::filter([=](Data::GroupCall *real) { + const auto call = _groupCall.get(); + return call && real && (real->id() == call->id()); + }) | rpl::take( + 1 + ) | rpl::map([=](not_null real) { + return HistoryView::GroupCallTracker::ContentByCall( + real, + HistoryView::UserpicsInRowStyle{ + .size = st::groupCallTopBarUserpicSize, + .shift = st::groupCallTopBarUserpicShift, + .stroke = st::groupCallTopBarUserpicStroke, + }); + }) | rpl::flatten_latest( + ) | rpl::start_with_next([=](const Ui::GroupCallBarContent &content) { + _userpics = content.userpics; + update(); + }, lifetime()); +} + void TopBar::updateInfoLabels() { setInfoLabels(); updateControlsGeometry(); @@ -251,8 +288,12 @@ void TopBar::updateControlsGeometry() { } auto right = st::callBarRightSkip; - _hangupLabel->moveToRight(right, st::callBarLabelTop); - right += _hangupLabel->width(); + if (_hangupLabel) { + _hangupLabel->moveToRight(right, st::callBarLabelTop); + right += _hangupLabel->width(); + } else { + //right -= st::callBarRightSkip; + } right += st::callBarHangup.width; _hangup->setGeometryToRight(0, 0, right, height()); _info->setGeometryToLeft( @@ -283,6 +324,12 @@ void TopBar::updateControlsGeometry() { void TopBar::paintEvent(QPaintEvent *e) { Painter p(this); p.fillRect(e->rect(), _muted ? st::callBarBgMuted : st::callBarBg); + if (!_userpics.isNull()) { + const auto imageSize = _userpics.size() + / _userpics.devicePixelRatio(); + const auto top = (height() - imageSize.height()) / 2; + p.drawImage(_mute->width(), top, _userpics); + } } TopBar::~TopBar() = default; diff --git a/Telegram/SourceFiles/calls/calls_top_bar.h b/Telegram/SourceFiles/calls/calls_top_bar.h index 20c964187..9871284e1 100644 --- a/Telegram/SourceFiles/calls/calls_top_bar.h +++ b/Telegram/SourceFiles/calls/calls_top_bar.h @@ -54,10 +54,13 @@ private: void startDurationUpdateTimer(crl::time currentDuration); void setMuted(bool mute); + void subscribeToMembersChanges(not_null call); + const base::weak_ptr _call; const base::weak_ptr _groupCall; bool _muted = false; + QImage _userpics; object_ptr _durationLabel; object_ptr _signalBars; object_ptr _fullInfoLabel; diff --git a/Telegram/SourceFiles/history/view/history_view_group_call_tracker.cpp b/Telegram/SourceFiles/history/view/history_view_group_call_tracker.cpp index b61969c26..77a97d8ce 100644 --- a/Telegram/SourceFiles/history/view/history_view_group_call_tracker.cpp +++ b/Telegram/SourceFiles/history/view/history_view_group_call_tracker.cpp @@ -192,7 +192,18 @@ rpl::producer GroupCallTracker::ContentByCall( // Full kLimit of speaking userpics already. return false; } + + // Add the new speaking to the place we found. const auto added = state->userpics.insert(i, UserpicInRow{ user }); + + // Remove him from the tail, if he was there. + for (auto i = added + 1; i != state->userpics.end(); ++i) { + if (i->peer == user) { + state->userpics.erase(i); + break; + } + } + if (state->userpics.size() > kLimit) { // Find last non-speaking userpic to remove. It must be there. for (auto i = state->userpics.end() - 1; i != added; --i) { diff --git a/Telegram/SourceFiles/ui/chat/group_call_bar.cpp b/Telegram/SourceFiles/ui/chat/group_call_bar.cpp index 584f902e6..cff4ed1f5 100644 --- a/Telegram/SourceFiles/ui/chat/group_call_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/group_call_bar.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/widgets/buttons.h" #include "lang/lang_keys.h" #include "styles/style_chat.h" +#include "styles/style_calls.h" #include "styles/palette.h" #include @@ -23,6 +24,10 @@ GroupCallBar::GroupCallBar( rpl::producer content) : _wrap(parent, object_ptr(parent)) , _inner(_wrap.entity()) +, _join(std::make_unique( + _inner.get(), + tr::lng_group_call_join(), + st::groupCallTopBarJoin)) , _shadow(std::make_unique(_wrap.parentWidget())) { _wrap.hide(anim::type::instant); _shadow->hide(); @@ -72,7 +77,6 @@ void GroupCallBar::setupInner() { paint(p); }, _inner->lifetime()); - // Clicks. _inner->setCursor(style::cur_pointer); _inner->events( @@ -91,6 +95,16 @@ void GroupCallBar::setupInner() { return rpl::empty_value(); }) | rpl::start_to_stream(_barClicks, _inner->lifetime()); + rpl::combine( + _inner->widthValue(), + _join->widthValue() + ) | rpl::start_with_next([=](int outerWidth, int) { + // Skip shadow of the bar above. + const auto top = (st::historyReplyHeight + - st::lineWidth + - _join->height()) / 2 + st::lineWidth; + _join->moveToRight(top, top, outerWidth); + }, _join->lifetime()); _wrap.geometryValue( ) | rpl::start_with_next([=](QRect rect) { @@ -106,10 +120,11 @@ void GroupCallBar::paint(Painter &p) { if (!_content.userpics.isNull()) { const auto imageSize = _content.userpics.size() / _content.userpics.devicePixelRatio(); - p.drawImage( - left, - (_inner->height() - imageSize.height()) / 2, - _content.userpics); + // Skip shadow of the bar above. + const auto imageTop = (st::historyReplyHeight + - st::lineWidth + - imageSize.height()) / 2 + st::lineWidth; + p.drawImage(left, imageTop, _content.userpics); left += imageSize.width() + st::msgReplyBarSkip; } const auto titleTop = st::msgReplyPadding.top(); @@ -207,7 +222,7 @@ rpl::producer<> GroupCallBar::barClicks() const { } rpl::producer<> GroupCallBar::joinClicks() const { - return rpl::never<>(); + return _join->clicks() | rpl::to_empty; } } // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/group_call_bar.h b/Telegram/SourceFiles/ui/chat/group_call_bar.h index 1796330c1..9fba26326 100644 --- a/Telegram/SourceFiles/ui/chat/group_call_bar.h +++ b/Telegram/SourceFiles/ui/chat/group_call_bar.h @@ -15,6 +15,7 @@ class Painter; namespace Ui { class PlainShadow; +class RoundButton; struct GroupCallBarContent { int count = 0; @@ -53,9 +54,10 @@ private: void setupInner(); void paint(Painter &p); - Ui::SlideWrap<> _wrap; - not_null _inner; - std::unique_ptr _shadow; + SlideWrap<> _wrap; + not_null _inner; + std::unique_ptr _join; + std::unique_ptr _shadow; rpl::event_stream<> _barClicks; Fn _shadowGeometryPostprocess; bool _shouldBeShown = false;