Show nice confcall invites.

This commit is contained in:
John Preston 2025-04-01 21:50:39 +05:00
parent aaa37a3e0d
commit 09229812f4
14 changed files with 170 additions and 29 deletions

View file

@ -4671,18 +4671,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_call_outgoing" = "Outgoing call"; "lng_call_outgoing" = "Outgoing call";
"lng_call_video_outgoing" = "Outgoing video call"; "lng_call_video_outgoing" = "Outgoing video call";
"lng_call_group_outgoing" = "Outgoing group call";
"lng_call_incoming" = "Incoming call"; "lng_call_incoming" = "Incoming call";
"lng_call_video_incoming" = "Incoming video call"; "lng_call_video_incoming" = "Incoming video call";
"lng_call_group_incoming" = "Incoming group call";
"lng_call_missed" = "Missed call"; "lng_call_missed" = "Missed call";
"lng_call_video_missed" = "Missed video call"; "lng_call_video_missed" = "Missed video call";
"lng_call_group_missed" = "Missed group call";
"lng_call_cancelled" = "Canceled call"; "lng_call_cancelled" = "Canceled call";
"lng_call_video_cancelled" = "Canceled video call"; "lng_call_video_cancelled" = "Canceled video call";
"lng_call_declined" = "Declined call"; "lng_call_declined" = "Declined call";
"lng_call_video_declined" = "Declined video call"; "lng_call_video_declined" = "Declined video call";
"lng_call_group_declined" = "Declined group call";
"lng_call_duration_info" = "{time}, {duration}"; "lng_call_duration_info" = "{time}, {duration}";
"lng_call_type_and_duration" = "{type} ({duration})"; "lng_call_type_and_duration" = "{type} ({duration})";
"lng_call_invitation" = "Call invitation"; "lng_call_invitation" = "Group call invitation";
"lng_call_ongoing" = "Ongoing call"; "lng_call_ongoing" = "Ongoing group call";
"lng_call_rate_label" = "Please rate the quality of your call"; "lng_call_rate_label" = "Please rate the quality of your call";
"lng_call_rate_comment" = "Comment (optional)"; "lng_call_rate_comment" = "Comment (optional)";

View file

@ -26,8 +26,10 @@ UserpicButton {
} }
UserpicsRow { UserpicsRow {
button: UserpicButton; button: UserpicButton;
bg: color;
shift: pixels; shift: pixels;
stroke: pixels; stroke: pixels;
complex: bool;
invert: bool; invert: bool;
} }
ShortInfoBox { ShortInfoBox {

View file

@ -694,8 +694,7 @@ object_ptr<Ui::RpWidget> CreateUserpicsWithMoreBadge(
bool painting = false; bool painting = false;
}; };
const auto full = st.button.size.height() const auto full = st.button.size.height()
+ st::boostReplaceIconAdd.y() + (st.complex ? (st::boostReplaceIconAdd.y() + st::lineWidth) : 0);
+ st::lineWidth;
auto result = object_ptr<Ui::FixedHeightWidget>(parent, full); auto result = object_ptr<Ui::FixedHeightWidget>(parent, full);
const auto raw = result.data(); const auto raw = result.data();
const auto overlay = CreateChild<Ui::RpWidget>(raw); const auto overlay = CreateChild<Ui::RpWidget>(raw);
@ -731,6 +730,12 @@ object_ptr<Ui::RpWidget> CreateUserpicsWithMoreBadge(
overlay->update(); overlay->update();
}, raw->lifetime()); }, raw->lifetime());
if (const auto count = state->count.current()) {
const auto single = st.button.size.width();
const auto used = std::min(count, int(state->buttons.size()));
const auto shift = st.shift;
raw->resize(used ? (single + (used - 1) * shift) : 0, raw->height());
}
rpl::combine( rpl::combine(
raw->widthValue(), raw->widthValue(),
state->count.value() state->count.value()
@ -768,7 +773,7 @@ object_ptr<Ui::RpWidget> CreateUserpicsWithMoreBadge(
auto hq = PainterHighQualityEnabler(q); auto hq = PainterHighQualityEnabler(q);
const auto stroke = st.stroke; const auto stroke = st.stroke;
const auto half = stroke / 2.; const auto half = stroke / 2.;
auto pen = st::windowBg->p; auto pen = st.bg->p;
pen.setWidthF(stroke * 2.); pen.setWidthF(stroke * 2.);
state->painting = true; state->painting = true;
const auto paintOne = [&](not_null<Ui::UserpicButton*> button) { const auto paintOne = [&](not_null<Ui::UserpicButton*> button) {
@ -788,18 +793,18 @@ object_ptr<Ui::RpWidget> CreateUserpicsWithMoreBadge(
} }
} }
state->painting = false; state->painting = false;
const auto last = state->buttons.back().get();
const auto add = st::boostReplaceIconAdd;
const auto skip = st::boostReplaceIconSkip;
const auto w = st::boostReplaceIcon.width() + 2 * skip;
const auto h = st::boostReplaceIcon.height() + 2 * skip;
const auto x = last->x() + last->width() - w + add.x();
const auto y = last->y() + last->height() - h + add.y();
const auto text = (state->count.current() > limit) const auto text = (state->count.current() > limit)
? ('+' + QString::number(state->count.current() - limit)) ? ('+' + QString::number(state->count.current() - limit))
: QString(); : QString();
if (!text.isEmpty()) { if (st.complex && !text.isEmpty()) {
const auto last = state->buttons.back().get();
const auto add = st::boostReplaceIconAdd;
const auto skip = st::boostReplaceIconSkip;
const auto w = st::boostReplaceIcon.width() + 2 * skip;
const auto h = st::boostReplaceIcon.height() + 2 * skip;
const auto x = last->x() + last->width() - w + add.x();
const auto y = last->y() + last->height() - h + add.y();
const auto &font = st::semiboldFont; const auto &font = st::semiboldFont;
const auto width = font->width(text); const auto width = font->width(text);
const auto padded = std::max(w, width + 2 * font->spacew); const auto padded = std::max(w, width + 2 * font->spacew);

View file

@ -37,6 +37,7 @@ CallBodyLayout {
photoSize: pixels; photoSize: pixels;
nameTop: pixels; nameTop: pixels;
statusTop: pixels; statusTop: pixels;
participantsTop: pixels;
muteStroke: pixels; muteStroke: pixels;
muteSize: pixels; muteSize: pixels;
mutePosition: point; mutePosition: point;
@ -48,6 +49,7 @@ callBodyLayout: CallBodyLayout {
photoSize: 160px; photoSize: 160px;
nameTop: 221px; nameTop: 221px;
statusTop: 254px; statusTop: 254px;
participantsTop: 294px;
muteStroke: 3px; muteStroke: 3px;
muteSize: 36px; muteSize: 36px;
mutePosition: point(142px, 135px); mutePosition: point(142px, 135px);
@ -58,6 +60,7 @@ callBodyWithPreview: CallBodyLayout {
photoSize: 100px; photoSize: 100px;
nameTop: 132px; nameTop: 132px;
statusTop: 163px; statusTop: 163px;
participantsTop: 193px;
muteStroke: 3px; muteStroke: 3px;
muteSize: 0px; muteSize: 0px;
mutePosition: point(90px, 84px); mutePosition: point(90px, 84px);
@ -1538,11 +1541,27 @@ confcallJoinUserpics: UserpicsRow {
size: size(36px, 36px); size: size(36px, 36px);
photoSize: 36px; photoSize: 36px;
} }
bg: boxBg;
shift: 16px; shift: 16px;
stroke: 2px; stroke: 2px;
invert: true; invert: true;
} }
confcallJoinUserpicsPadding: margins(0px, 0px, 0px, 16px); confcallJoinUserpicsPadding: margins(0px, 0px, 0px, 16px);
confcallInviteUserpicsBg: groupCallMembersBg;
confcallInviteUserpics: UserpicsRow {
button: UserpicButton(defaultUserpicButton) {
size: size(24px, 24px);
photoSize: 24px;
}
bg: confcallInviteUserpicsBg;
shift: 10px;
stroke: 2px;
invert: true;
}
confcallInviteParticipants: FlatLabel(defaultFlatLabel) {
textFg: callNameFg;
}
confcallInviteParticipantsPadding: margins(8px, 3px, 12px, 2px);
confcallInviteVideo: IconButton { confcallInviteVideo: IconButton {
width: 36px; width: 36px;
height: 52px; height: 52px;

View file

@ -253,6 +253,7 @@ Call::Call(
not_null<UserData*> user, not_null<UserData*> user,
CallId conferenceId, CallId conferenceId,
MsgId conferenceInviteMsgId, MsgId conferenceInviteMsgId,
std::vector<not_null<PeerData*>> conferenceParticipants,
bool video) bool video)
: _delegate(delegate) : _delegate(delegate)
, _user(user) , _user(user)
@ -279,6 +280,7 @@ Call::Call(
, _id(base::RandomValue<CallId>()) , _id(base::RandomValue<CallId>())
, _conferenceId(conferenceId) , _conferenceId(conferenceId)
, _conferenceInviteMsgId(conferenceInviteMsgId) , _conferenceInviteMsgId(conferenceInviteMsgId)
, _conferenceParticipants(std::move(conferenceParticipants))
, _videoIncoming( , _videoIncoming(
std::make_unique<Webrtc::VideoTrack>( std::make_unique<Webrtc::VideoTrack>(
StartVideoState(video))) StartVideoState(video)))

View file

@ -107,6 +107,7 @@ public:
not_null<UserData*> user, not_null<UserData*> user,
CallId conferenceId, CallId conferenceId,
MsgId conferenceInviteMsgId, MsgId conferenceInviteMsgId,
std::vector<not_null<PeerData*>> conferenceParticipants,
bool video); bool video);
[[nodiscard]] Type type() const { [[nodiscard]] Type type() const {
@ -127,6 +128,10 @@ public:
[[nodiscard]] MsgId conferenceInviteMsgId() const { [[nodiscard]] MsgId conferenceInviteMsgId() const {
return _conferenceInviteMsgId; return _conferenceInviteMsgId;
} }
[[nodiscard]] auto conferenceParticipants() const
-> const std::vector<not_null<PeerData*>> & {
return _conferenceParticipants;
}
[[nodiscard]] bool isIncomingWaiting() const; [[nodiscard]] bool isIncomingWaiting() const;
void start(bytes::const_span random); void start(bytes::const_span random);
@ -343,6 +348,7 @@ private:
CallId _conferenceId = 0; CallId _conferenceId = 0;
MsgId _conferenceInviteMsgId = 0; MsgId _conferenceInviteMsgId = 0;
std::vector<not_null<PeerData*>> _conferenceParticipants;
std::unique_ptr<tgcalls::Instance> _instance; std::unique_ptr<tgcalls::Instance> _instance;
std::shared_ptr<tgcalls::VideoCaptureInterface> _videoCapture; std::shared_ptr<tgcalls::VideoCaptureInterface> _videoCapture;

View file

@ -1024,6 +1024,11 @@ void Instance::showConferenceInvite(
return; return;
} }
auto conferenceParticipants = call->otherParticipants;
if (!ranges::contains(conferenceParticipants, user)) {
conferenceParticipants.push_back(user);
}
const auto &config = user->session().serverConfig(); const auto &config = user->session().serverConfig();
if (inCall() || inGroupCall()) { if (inCall() || inGroupCall()) {
declineIncomingConferenceInvites(conferenceId); declineIncomingConferenceInvites(conferenceId);
@ -1038,6 +1043,7 @@ void Instance::showConferenceInvite(
user, user,
conferenceId, conferenceId,
conferenceInviteMsgId, conferenceInviteMsgId,
std::move(conferenceParticipants),
video); video);
const auto raw = call.get(); const auto raw = call.get();

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "calls/calls_panel.h" #include "calls/calls_panel.h"
#include "boxes/peers/replace_boost_box.h" // CreateUserpicsWithMoreBadge
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_user.h" #include "data/data_user.h"
@ -215,6 +216,7 @@ Panel::Panel(not_null<Call*> call)
initWindow(); initWindow();
initWidget(); initWidget();
initControls(); initControls();
initConferenceInvite();
initLayout(); initLayout();
initMediaDeviceToggles(); initMediaDeviceToggles();
showAndActivate(); showAndActivate();
@ -534,6 +536,65 @@ void Panel::initControls() {
_screencast->finishAnimating(); _screencast->finishAnimating();
} }
void Panel::initConferenceInvite() {
const auto &participants = _call->conferenceParticipants();
const auto count = int(participants.size());
if (count < 2) {
return;
}
_conferenceParticipants.create(widget());
_conferenceParticipants->show();
const auto raw = _conferenceParticipants.data();
auto peers = std::vector<not_null<PeerData*>>();
for (const auto &peer : participants) {
if (peer == _user && count > 3) {
continue;
}
peers.push_back(peer);
if (peers.size() == 3) {
break;
}
}
const auto userpics = CreateUserpicsWithMoreBadge(
raw,
rpl::single(peers),
st::confcallInviteUserpics,
peers.size()).release();
const auto label = Ui::CreateChild<Ui::FlatLabel>(
raw,
tr::lng_group_call_members(tr::now, lt_count, count),
st::confcallInviteParticipants);
const auto padding = st::confcallInviteParticipantsPadding;
const auto add = padding.bottom();
const auto width = add
+ userpics->width()
+ padding.left()
+ label->width()
+ padding.right();
const auto height = add + userpics->height() + add;
_status->geometryValue() | rpl::start_with_next([=] {
const auto top = _bodyTop + _bodySt->participantsTop;
const auto left = (widget()->width() - width) / 2;
raw->setGeometry(left, top, width, height);
userpics->move(add, add);
label->move(add + userpics->width() + padding.left(), padding.top());
}, raw->lifetime());
raw->paintRequest() | rpl::start_with_next([=] {
auto p = QPainter(raw);
auto hq = PainterHighQualityEnabler(p);
const auto radius = raw->height() / 2.;
p.setPen(Qt::NoPen);
p.setBrush(st::confcallInviteUserpicsBg);
p.drawRoundedRect(raw->rect(), radius, radius);
}, raw->lifetime());
}
void Panel::setIncomingSize(QSize size) { void Panel::setIncomingSize(QSize size) {
if (_incomingFrameSize == size) { if (_incomingFrameSize == size) {
return; return;
@ -1160,7 +1221,11 @@ void Panel::updateControlsGeometry() {
std::min( std::min(
bodyPreviewSizeMax.height(), bodyPreviewSizeMax.height(),
st::callOutgoingPreviewMax.height())); st::callOutgoingPreviewMax.height()));
const auto contentHeight = _bodySt->height const auto bodyContentHeight = _bodySt->height
+ (_conferenceParticipants
? (_bodySt->participantsTop - _bodySt->statusTop)
: 0);
const auto contentHeight = bodyContentHeight
+ (_outgoingPreviewInBody ? bodyPreviewSize.height() : 0); + (_outgoingPreviewInBody ? bodyPreviewSize.height() : 0);
const auto remainingHeight = available - contentHeight; const auto remainingHeight = available - contentHeight;
const auto skipHeight = remainingHeight const auto skipHeight = remainingHeight
@ -1172,7 +1237,7 @@ void Panel::updateControlsGeometry() {
widget()->height(), widget()->height(),
_buttonsTopShown, _buttonsTopShown,
shown); shown);
const auto previewTop = _bodyTop + _bodySt->height + skipHeight; const auto previewTop = _bodyTop + bodyContentHeight + skipHeight;
_userpic->setGeometry( _userpic->setGeometry(
(widget()->width() - _bodySt->photoSize) / 2, (widget()->width() - _bodySt->photoSize) / 2,

View file

@ -142,6 +142,7 @@ private:
void initWindow(); void initWindow();
void initWidget(); void initWidget();
void initControls(); void initControls();
void initConferenceInvite();
void reinitWithCall(Call *call); void reinitWithCall(Call *call);
void initLayout(); void initLayout();
void initMediaDeviceToggles(); void initMediaDeviceToggles();
@ -211,6 +212,7 @@ private:
object_ptr < Ui::FadeWrap<Ui::CallButton>> _addPeople; object_ptr < Ui::FadeWrap<Ui::CallButton>> _addPeople;
object_ptr<Ui::FlatLabel> _name; object_ptr<Ui::FlatLabel> _name;
object_ptr<Ui::FlatLabel> _status; object_ptr<Ui::FlatLabel> _status;
object_ptr<Ui::RpWidget> _conferenceParticipants = { nullptr };
object_ptr<Ui::RpWidget> _fingerprint = { nullptr }; object_ptr<Ui::RpWidget> _fingerprint = { nullptr };
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteAudioMute = { nullptr }; object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteAudioMute = { nullptr };
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteLowBattery object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _remoteLowBattery

View file

@ -456,7 +456,9 @@ Invoice ComputeInvoiceData(
return result; return result;
} }
Call ComputeCallData(const MTPDmessageActionPhoneCall &call) { Call ComputeCallData(
not_null<Session*> owner,
const MTPDmessageActionPhoneCall &call) {
auto result = Call(); auto result = Call();
result.state = [&] { result.state = [&] {
if (const auto reason = call.vreason()) { if (const auto reason = call.vreason()) {
@ -480,8 +482,18 @@ Call ComputeCallData(const MTPDmessageActionPhoneCall &call) {
return result; return result;
} }
Call ComputeCallData(const MTPDmessageActionConferenceCall &call) { Call ComputeCallData(
not_null<Session*> owner,
const MTPDmessageActionConferenceCall &call) {
auto participants = std::vector<not_null<PeerData*>>();
if (const auto list = call.vother_participants()) {
participants.reserve(list->v.size());
for (const auto &participant : list->v) {
participants.push_back(owner->peer(peerFromMTP(participant)));
}
}
return { return {
.otherParticipants = std::move(participants),
.conferenceId = call.vcall_id().v, .conferenceId = call.vcall_id().v,
.duration = call.vduration().value_or_empty(), .duration = call.vduration().value_or_empty(),
.state = (call.vduration().value_or_empty() .state = (call.vduration().value_or_empty()
@ -1723,7 +1735,8 @@ const Call *MediaCall::call() const {
} }
TextWithEntities MediaCall::notificationText() const { TextWithEntities MediaCall::notificationText() const {
auto result = Text(parent(), _call.state, _call.video); const auto conference = (_call.conferenceId != 0);
auto result = Text(parent(), _call.state, conference, _call.video);
if (_call.duration > 0) { if (_call.duration > 0) {
result = tr::lng_call_type_and_duration( result = tr::lng_call_type_and_duration(
tr::now, tr::now,
@ -1765,6 +1778,7 @@ std::unique_ptr<HistoryView::Media> MediaCall::createView(
QString MediaCall::Text( QString MediaCall::Text(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
CallState state, CallState state,
bool conference,
bool video) { bool video) {
if (state == CallState::Invitation) { if (state == CallState::Invitation) {
return tr::lng_call_invitation(tr::now); return tr::lng_call_invitation(tr::now);
@ -1772,14 +1786,20 @@ QString MediaCall::Text(
return tr::lng_call_ongoing(tr::now); return tr::lng_call_ongoing(tr::now);
} else if (item->out()) { } else if (item->out()) {
return ((state == CallState::Missed) return ((state == CallState::Missed)
? (video ? (conference
? tr::lng_call_group_declined
: video
? tr::lng_call_video_cancelled ? tr::lng_call_video_cancelled
: tr::lng_call_cancelled) : tr::lng_call_cancelled)
: (video : (conference
? tr::lng_call_group_outgoing
: video
? tr::lng_call_video_outgoing ? tr::lng_call_video_outgoing
: tr::lng_call_outgoing))(tr::now); : tr::lng_call_outgoing))(tr::now);
} else if (state == CallState::Missed) { } else if (state == CallState::Missed) {
return (video return (conference
? tr::lng_call_group_missed
: video
? tr::lng_call_video_missed ? tr::lng_call_video_missed
: tr::lng_call_missed)(tr::now); : tr::lng_call_missed)(tr::now);
} else if (state == CallState::Busy) { } else if (state == CallState::Busy) {
@ -1787,7 +1807,9 @@ QString MediaCall::Text(
? tr::lng_call_video_declined ? tr::lng_call_video_declined
: tr::lng_call_declined)(tr::now); : tr::lng_call_declined)(tr::now);
} }
return (video return (conference
? tr::lng_call_group_incoming
: video
? tr::lng_call_video_incoming ? tr::lng_call_video_incoming
: tr::lng_call_incoming)(tr::now); : tr::lng_call_incoming)(tr::now);
} }

View file

@ -82,6 +82,7 @@ struct SharedContact final {
struct Call { struct Call {
using State = CallState; using State = CallState;
std::vector<not_null<PeerData*>> otherParticipants;
CallId conferenceId = 0; CallId conferenceId = 0;
int duration = 0; int duration = 0;
State state = State::Missed; State state = State::Missed;
@ -468,6 +469,7 @@ public:
[[nodiscard]] static QString Text( [[nodiscard]] static QString Text(
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
CallState state, CallState state,
bool conference,
bool video); bool video);
private: private:
@ -801,8 +803,11 @@ private:
not_null<HistoryItem*> item, not_null<HistoryItem*> item,
const MTPDmessageMediaPaidMedia &data); const MTPDmessageMediaPaidMedia &data);
[[nodiscard]] Call ComputeCallData(const MTPDmessageActionPhoneCall &call);
[[nodiscard]] Call ComputeCallData( [[nodiscard]] Call ComputeCallData(
not_null<Session*> owner,
const MTPDmessageActionPhoneCall &call);
[[nodiscard]] Call ComputeCallData(
not_null<Session*> owner,
const MTPDmessageActionConferenceCall &call); const MTPDmessageActionConferenceCall &call);
[[nodiscard]] GiveawayStart ComputeGiveawayStartData( [[nodiscard]] GiveawayStart ComputeGiveawayStartData(

View file

@ -481,13 +481,13 @@ HistoryItem::HistoryItem(
createComponents(CreateConfig()); createComponents(CreateConfig());
_media = std::make_unique<Data::MediaCall>( _media = std::make_unique<Data::MediaCall>(
this, this,
Data::ComputeCallData(data)); Data::ComputeCallData(&history->owner(), data));
setTextValue({}); setTextValue({});
}, [&](const MTPDmessageActionConferenceCall &data) { }, [&](const MTPDmessageActionConferenceCall &data) {
createComponents(CreateConfig()); createComponents(CreateConfig());
_media = std::make_unique<Data::MediaCall>( _media = std::make_unique<Data::MediaCall>(
this, this,
Data::ComputeCallData(data)); Data::ComputeCallData(&history->owner(), data));
setTextValue({}); setTextValue({});
}, [&](const auto &) { }, [&](const auto &) {
createServiceFromMtp(data); createServiceFromMtp(data);
@ -1906,6 +1906,7 @@ void HistoryItem::applyEdition(const MTPDmessageService &message) {
_media = std::make_unique<Data::MediaCall>( _media = std::make_unique<Data::MediaCall>(
this, this,
Data::ComputeCallData( Data::ComputeCallData(
&history()->owner(),
message.vaction().c_messageActionConferenceCall())); message.vaction().c_messageActionConferenceCall()));
addToSharedMediaIndex(); addToSharedMediaIndex();
finishEdition(-1); finishEdition(-1);

View file

@ -47,7 +47,7 @@ Call::Call(
, _conference(call->conferenceId != 0) , _conference(call->conferenceId != 0)
, _video(call->video) { , _video(call->video) {
const auto item = parent->data(); const auto item = parent->data();
_text = Data::MediaCall::Text(item, _state, _video); _text = Data::MediaCall::Text(item, _state, _conference, _video);
_status = QLocale().toString( _status = QLocale().toString(
parent->dateTime().time(), parent->dateTime().time(),
QLocale::ShortFormat); QLocale::ShortFormat);
@ -118,10 +118,10 @@ void Call::draw(Painter &p, const PaintContext &context) const {
p.setPen(stm->mediaFg); p.setPen(stm->mediaFg);
p.drawTextLeft(statusleft, statustop, paintw, _status); p.drawTextLeft(statusleft, statustop, paintw, _status);
const auto &icon = _conference const auto &icon = _video
? stm->historyCallGroupIcon
: _video
? stm->historyCallCameraIcon ? stm->historyCallCameraIcon
: _conference
? stm->historyCallGroupIcon
: stm->historyCallIcon; : stm->historyCallIcon;
icon.paint(p, paintw - st::historyCallIconPosition.x() - icon.width(), st::historyCallIconPosition.y() - topMinus, paintw); icon.paint(p, paintw - st::historyCallIconPosition.x() - icon.width(), st::historyCallIconPosition.y() - topMinus, paintw);
} }

View file

@ -313,8 +313,10 @@ boostReplaceIconAdd: point(4px, 2px);
boostReplaceArrow: icon{{ "mediaview/next", windowSubTextFg }}; boostReplaceArrow: icon{{ "mediaview/next", windowSubTextFg }};
boostReplaceUserpicsRow: UserpicsRow { boostReplaceUserpicsRow: UserpicsRow {
button: boostReplaceUserpic; button: boostReplaceUserpic;
bg: windowBg;
shift: boostReplaceUserpicsShift; shift: boostReplaceUserpicsShift;
stroke: boostReplaceIconOutline; stroke: boostReplaceIconOutline;
complex: true;
} }
showOrIconLastSeen: icon{{ "settings/premium/large_lastseen", windowFgActive }}; showOrIconLastSeen: icon{{ "settings/premium/large_lastseen", windowFgActive }};