Start group call members list.

This commit is contained in:
John Preston 2020-11-25 17:09:59 +03:00
parent 6a86ed1506
commit 2e62eb1186
93 changed files with 797 additions and 149 deletions

View File

@ -266,6 +266,8 @@ PRIVATE
calls/calls_call.h
calls/calls_group_call.cpp
calls/calls_group_call.h
calls/calls_group_members.cpp
calls/calls_group_members.h
calls/calls_group_panel.cpp
calls/calls_group_panel.h
calls/calls_emoji_fingerprint.cpp

View File

Before

Width:  |  Height:  |  Size: 595 B

After

Width:  |  Height:  |  Size: 595 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 209 B

View File

Before

Width:  |  Height:  |  Size: 306 B

After

Width:  |  Height:  |  Size: 306 B

View File

Before

Width:  |  Height:  |  Size: 449 B

After

Width:  |  Height:  |  Size: 449 B

View File

Before

Width:  |  Height:  |  Size: 211 B

After

Width:  |  Height:  |  Size: 211 B

View File

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 298 B

View File

Before

Width:  |  Height:  |  Size: 443 B

After

Width:  |  Height:  |  Size: 443 B

View File

Before

Width:  |  Height:  |  Size: 377 B

After

Width:  |  Height:  |  Size: 377 B

View File

Before

Width:  |  Height:  |  Size: 733 B

After

Width:  |  Height:  |  Size: 733 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 727 B

After

Width:  |  Height:  |  Size: 727 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 214 B

After

Width:  |  Height:  |  Size: 214 B

View File

Before

Width:  |  Height:  |  Size: 426 B

After

Width:  |  Height:  |  Size: 426 B

View File

Before

Width:  |  Height:  |  Size: 912 B

After

Width:  |  Height:  |  Size: 912 B

View File

Before

Width:  |  Height:  |  Size: 460 B

After

Width:  |  Height:  |  Size: 460 B

View File

Before

Width:  |  Height:  |  Size: 970 B

After

Width:  |  Height:  |  Size: 970 B

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 666 B

After

Width:  |  Height:  |  Size: 666 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

Before

Width:  |  Height:  |  Size: 560 B

After

Width:  |  Height:  |  Size: 560 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 489 B

After

Width:  |  Height:  |  Size: 489 B

View File

Before

Width:  |  Height:  |  Size: 1002 B

After

Width:  |  Height:  |  Size: 1002 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 744 B

After

Width:  |  Height:  |  Size: 744 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

Before

Width:  |  Height:  |  Size: 100 B

After

Width:  |  Height:  |  Size: 100 B

View File

Before

Width:  |  Height:  |  Size: 125 B

After

Width:  |  Height:  |  Size: 125 B

View File

Before

Width:  |  Height:  |  Size: 139 B

After

Width:  |  Height:  |  Size: 139 B

View File

Before

Width:  |  Height:  |  Size: 103 B

After

Width:  |  Height:  |  Size: 103 B

View File

Before

Width:  |  Height:  |  Size: 127 B

After

Width:  |  Height:  |  Size: 127 B

View File

Before

Width:  |  Height:  |  Size: 141 B

After

Width:  |  Height:  |  Size: 141 B

View File

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 295 B

View File

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 559 B

View File

Before

Width:  |  Height:  |  Size: 927 B

After

Width:  |  Height:  |  Size: 927 B

View File

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 305 B

View File

Before

Width:  |  Height:  |  Size: 524 B

After

Width:  |  Height:  |  Size: 524 B

View File

Before

Width:  |  Height:  |  Size: 820 B

After

Width:  |  Height:  |  Size: 820 B

View File

Before

Width:  |  Height:  |  Size: 385 B

After

Width:  |  Height:  |  Size: 385 B

View File

Before

Width:  |  Height:  |  Size: 873 B

After

Width:  |  Height:  |  Size: 873 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 230 B

After

Width:  |  Height:  |  Size: 230 B

View File

Before

Width:  |  Height:  |  Size: 393 B

After

Width:  |  Height:  |  Size: 393 B

View File

Before

Width:  |  Height:  |  Size: 616 B

After

Width:  |  Height:  |  Size: 616 B

View File

Before

Width:  |  Height:  |  Size: 333 B

After

Width:  |  Height:  |  Size: 333 B

View File

Before

Width:  |  Height:  |  Size: 552 B

After

Width:  |  Height:  |  Size: 552 B

View File

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 889 B

View File

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 173 B

View File

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 304 B

View File

Before

Width:  |  Height:  |  Size: 545 B

After

Width:  |  Height:  |  Size: 545 B

View File

Before

Width:  |  Height:  |  Size: 228 B

After

Width:  |  Height:  |  Size: 228 B

View File

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 420 B

View File

Before

Width:  |  Height:  |  Size: 661 B

After

Width:  |  Height:  |  Size: 661 B

View File

Before

Width:  |  Height:  |  Size: 637 B

After

Width:  |  Height:  |  Size: 637 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 545 B

After

Width:  |  Height:  |  Size: 545 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

View File

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 499 B

View File

Before

Width:  |  Height:  |  Size: 846 B

After

Width:  |  Height:  |  Size: 846 B

View File

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 420 B

View File

Before

Width:  |  Height:  |  Size: 715 B

After

Width:  |  Height:  |  Size: 715 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -219,7 +219,6 @@ contactsPhotoCheckIcon: defaultPeerListCheckIcon;
contactsPhotoCheck: defaultPeerListCheck;
contactsPhotoCheckbox: defaultPeerListCheckbox;
contactsPhotoDisabledCheckFg: menuIconFg;
contactsNameCheckedFg: windowActiveTextFg;
contactsRipple: defaultRippleAnimation;
contactsMarginTop: 4px;

View File

@ -1283,7 +1283,7 @@ crl::time PeerListContent::paintRow(
selected);
}
auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio();
p.setPen(anim::pen(st::contactsNameFg, st::contactsNameCheckedFg, nameCheckedRatio));
p.setPen(anim::pen(_st.item.nameFg, _st.item.nameFgChecked, nameCheckedRatio));
name.drawLeftElided(p, namex, _st.item.namePosition.y(), namew, width());
if (!actionSize.isEmpty()) {

View File

@ -135,7 +135,6 @@ private:
// Viewing admins, banned or restricted users list with search.
class ParticipantsBoxController
: public PeerListController
, private base::Subscriber
, public base::has_weak_ptr {
public:
using Role = ParticipantsRole;

View File

@ -22,14 +22,14 @@ CallSignalBars {
callRadius: 6px;
callShadow: Shadow {
left: icon {{ "call_shadow_left", windowShadowFg }};
topLeft: icon {{ "call_shadow_top_left", windowShadowFg }};
top: icon {{ "call_shadow_top", windowShadowFg }};
topRight: icon {{ "call_shadow_top_left-flip_horizontal", windowShadowFg }};
right: icon {{ "call_shadow_left-flip_horizontal", windowShadowFg }};
bottomRight: icon {{ "call_shadow_top_left-flip_vertical-flip_horizontal", windowShadowFg }};
bottom: icon {{ "call_shadow_top-flip_vertical", windowShadowFg }};
bottomLeft: icon {{ "call_shadow_top_left-flip_vertical", windowShadowFg }};
left: icon {{ "calls/call_shadow_left", windowShadowFg }};
topLeft: icon {{ "calls/call_shadow_top_left", windowShadowFg }};
top: icon {{ "calls/call_shadow_top", windowShadowFg }};
topRight: icon {{ "calls/call_shadow_top_left-flip_horizontal", windowShadowFg }};
right: icon {{ "calls/call_shadow_left-flip_horizontal", windowShadowFg }};
bottomRight: icon {{ "calls/call_shadow_top_left-flip_vertical-flip_horizontal", windowShadowFg }};
bottom: icon {{ "calls/call_shadow_top-flip_vertical", windowShadowFg }};
bottomLeft: icon {{ "calls/call_shadow_top_left-flip_vertical", windowShadowFg }};
extend: margins(9px, 8px, 9px, 10px);
fallback: windowShadowFgFallback;
}
@ -72,7 +72,7 @@ callBodyWithPreview: CallBodyLayout {
muteSize: 0px;
mutePosition: point(90px, 84px);
}
callMutedPeerIcon: icon {{ "calls_mute_userpic", callIconFg }};
callMutedPeerIcon: icon {{ "calls/calls_mute_userpic", callIconFg }};
callOutgoingPreviewMin: size(360px, 120px);
callOutgoingPreview: size(540px, 180px); // default, for height == callHeight.
@ -89,7 +89,7 @@ callSignalBarsPadding: margins(8px, 9px, 11px, 5px);
callFingerprintTop: 8px;
callFingerprintBottom: -16px;
callTooltipMutedIcon: icon{{ "calls_mute_tooltip", videoPlayIconFg }};
callTooltipMutedIcon: icon{{ "calls/calls_mute_tooltip", videoPlayIconFg }};
callTooltipMutedIconPosition: point(10px, 5px);
callTooltipPadding: margins(41px, 7px, 15px, 8px);
@ -114,7 +114,7 @@ callButtonLabel: FlatLabel(defaultFlatLabel) {
callAnswer: CallButton {
button: IconButton(callButton) {
icon: icon {{ "call_answer", callIconFg }};
icon: icon {{ "calls/call_answer", callIconFg }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: callAnswerRipple;
}
@ -127,7 +127,7 @@ callAnswer: CallButton {
}
callHangup: CallButton {
button: IconButton(callButton) {
icon: icon {{ "call_discard", callIconFg }};
icon: icon {{ "calls/call_discard", callIconFg }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: callHangupRipple;
}
@ -138,7 +138,7 @@ callHangup: CallButton {
}
callCancel: CallButton {
button: IconButton(callButton) {
icon: icon {{ "call_cancel", callIconFgActive }};
icon: icon {{ "calls/call_cancel", callIconFgActive }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: callIconActiveRipple;
}
@ -149,7 +149,7 @@ callCancel: CallButton {
}
callMicrophoneMute: CallButton {
button: IconButton(callButton) {
icon: icon {{ "call_record_active", callIconFg }};
icon: icon {{ "calls/call_record_active", callIconFg }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: callMuteRipple;
}
@ -160,7 +160,7 @@ callMicrophoneMute: CallButton {
}
callMicrophoneUnmute: CallButton(callMicrophoneMute) {
button: IconButton(callButton) {
icon: icon {{ "call_record_muted", callIconFgActive }};
icon: icon {{ "calls/call_record_muted", callIconFgActive }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: callIconActiveRipple;
}
@ -169,7 +169,7 @@ callMicrophoneUnmute: CallButton(callMicrophoneMute) {
}
callCameraMute: CallButton(callMicrophoneMute) {
button: IconButton(callButton) {
icon: icon {{ "call_camera_active", callIconFg }};
icon: icon {{ "calls/call_camera_active", callIconFg }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: callMuteRipple;
}
@ -177,7 +177,7 @@ callCameraMute: CallButton(callMicrophoneMute) {
}
callCameraUnmute: CallButton(callMicrophoneUnmute) {
button: IconButton(callButton) {
icon: icon {{ "call_camera_muted", callIconFgActive }};
icon: icon {{ "calls/call_camera_muted", callIconFgActive }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: callIconActiveRipple;
}
@ -223,7 +223,7 @@ callBarMuteToggle: IconButton {
width: 41px;
height: 38px;
icon: icon {{ "call_record_active", callBarFg }};
icon: icon {{ "calls/call_record_active", callBarFg }};
iconPosition: point(3px, 2px);
ripple: RippleAnimation(defaultRippleAnimation) {
@ -232,11 +232,11 @@ callBarMuteToggle: IconButton {
rippleAreaPosition: point(5px, 3px);
rippleAreaSize: 32px;
}
callBarUnmuteIcon: icon {{ "call_record_muted", callBarFg }};
callBarUnmuteIcon: icon {{ "calls/call_record_muted", callBarFg }};
callBarRightSkip: 12px;
callBarSkip: 10px;
callBarHangup: IconButton(callBarMuteToggle) {
icon: icon {{ "call_discard", callBarFg }};
icon: icon {{ "calls/call_discard", callBarFg }};
iconPosition: point(3px, 1px);
}
callBarLabel: LabelSimple(defaultLabelSimple) {
@ -254,16 +254,16 @@ callBarInfoLabel: FlatLabel(defaultFlatLabel) {
callBarLabelTop: 10px;
callArrowPosition: point(-2px, 1px);
callArrowIn: icon {{ "call_arrow_in", callArrowFg }};
callArrowOut: icon {{ "call_arrow_out", callArrowFg }};
callArrowMissed: icon {{ "call_arrow_in", callArrowMissedFg }};
callArrowIn: icon {{ "calls/call_arrow_in", callArrowFg }};
callArrowOut: icon {{ "calls/call_arrow_out", callArrowFg }};
callArrowMissed: icon {{ "calls/call_arrow_in", callArrowMissedFg }};
callArrowSkip: 4px;
callReDial: IconButton {
width: 40px;
height: 56px;
icon: icon {{ "call_answer", menuIconFg }};
iconOver: icon {{ "call_answer", menuIconFgOver }};
icon: icon {{ "calls/call_answer", menuIconFg }};
iconOver: icon {{ "calls/call_answer", menuIconFgOver }};
iconPosition: point(-1px, -1px);
ripple: defaultRippleAnimation;
@ -272,8 +272,8 @@ callReDial: IconButton {
}
callCameraReDial: IconButton(callReDial) {
icon: icon {{ "call_camera_active", menuIconFg }};
iconOver: icon {{ "call_camera_active", menuIconFgOver }};
icon: icon {{ "calls/call_camera_active", menuIconFg }};
iconOver: icon {{ "calls/call_camera_active", menuIconFgOver }};
}
callRatingPadding: margins(24px, 12px, 24px, 0px);
@ -281,7 +281,7 @@ callRatingStar: IconButton {
width: 36px;
height: 36px;
icon: icon {{ "call_rating", windowSubTextFg }};
icon: icon {{ "calls/call_rating", windowSubTextFg }};
iconPosition: point(-1px, -1px);
ripple: RippleAnimation(defaultRippleAnimation) {
@ -290,7 +290,7 @@ callRatingStar: IconButton {
rippleAreaPosition: point(0px, 0px);
rippleAreaSize: 36px;
}
callRatingStarFilled: icon {{ "call_rating_filled", lightButtonFg }};
callRatingStarFilled: icon {{ "calls/call_rating_filled", lightButtonFg }};
callRatingStarTop: 4px;
callRatingComment: InputField(defaultInputField) {
textMargins: margins(1px, 26px, 1px, 4px);
@ -327,43 +327,43 @@ callTitleButton: IconButton {
iconPosition: point(0px, 0px);
}
callTitleMinimizeIcon: icon {
{ "calls_minimize_shadow", windowShadowFg },
{ "calls_minimize_main", callNameFg },
{ "calls/calls_minimize_shadow", windowShadowFg },
{ "calls/calls_minimize_main", callNameFg },
};
callTitleMinimizeIconOver: icon {
{ size(34px, 30px), callBgButton },
{ size(34px, 30px), callMuteRipple },
{ "calls_minimize_shadow", windowShadowFg },
{ "calls_minimize_main", callNameFg },
{ "calls/calls_minimize_shadow", windowShadowFg },
{ "calls/calls_minimize_main", callNameFg },
};
callTitleMaximizeIcon: icon {
{ "calls_maximize_shadow", windowShadowFg },
{ "calls_maximize_main", callNameFg },
{ "calls/calls_maximize_shadow", windowShadowFg },
{ "calls/calls_maximize_main", callNameFg },
};
callTitleMaximizeIconOver: icon {
{ size(34px, 30px), callBgButton },
{ size(34px, 30px), callMuteRipple },
{ "calls_maximize_shadow", windowShadowFg },
{ "calls_maximize_main", callNameFg },
{ "calls/calls_maximize_shadow", windowShadowFg },
{ "calls/calls_maximize_main", callNameFg },
};
callTitleRestoreIcon: icon {
{ "calls_restore_shadow", windowShadowFg },
{ "calls_restore_main", callNameFg },
{ "calls/calls_restore_shadow", windowShadowFg },
{ "calls/calls_restore_main", callNameFg },
};
callTitleRestoreIconOver: icon {
{ size(34px, 30px), callBgButton },
{ size(34px, 30px), callMuteRipple },
{ "calls_restore_shadow", windowShadowFg },
{ "calls_restore_main", callNameFg },
{ "calls/calls_restore_shadow", windowShadowFg },
{ "calls/calls_restore_main", callNameFg },
};
callTitleCloseIcon: icon {
{ "calls_close_shadow", windowShadowFg },
{ "calls_close_main", callNameFg },
{ "calls/calls_close_shadow", windowShadowFg },
{ "calls/calls_close_main", callNameFg },
};
callTitleCloseIconOver: icon {
{ size(34px, 30px), titleButtonCloseBgOver },
{ "calls_close_shadow", windowShadowFg },
{ "calls_close_main", titleButtonCloseFgOver },
{ "calls/calls_close_shadow", windowShadowFg },
{ "calls/calls_close_main", titleButtonCloseFgOver },
};
callTitle: WindowTitle(defaultWindowTitle) {
height: 0px;
@ -394,7 +394,7 @@ callTitle: WindowTitle(defaultWindowTitle) {
closeIconActive: callTitleCloseIcon;
closeIconActiveOver: callTitleCloseIconOver;
}
callTitleShadow: icon {{ "calls_shadow_controls", windowShadowFg }};
callTitleShadow: icon {{ "calls/calls_shadow_controls", windowShadowFg }};
callErrorToast: Toast(defaultToast) {
minWidth: 240px;
@ -402,3 +402,78 @@ callErrorToast: Toast(defaultToast) {
groupCallWidth: 380px;
groupCallHeight: 580px;
groupCallRipple: RippleAnimation(defaultRippleAnimation) {
color: groupCallMembersRipple;
}
groupCallMembersList: PeerList(defaultPeerList) {
item: PeerListItem(defaultPeerListItem) {
button: OutlineButton(defaultPeerListButton) {
textBg: groupCallMembersBg;
textBgOver: groupCallMembersBg;
textFg: groupCallMemberInactiveStatus;
textFgOver: groupCallMemberInactiveStatus;
font: normalFont;
padding: margins(11px, 5px, 11px, 5px);
ripple: groupCallRipple;
}
height: 52px;
photoPosition: point(12px, 6px);
namePosition: point(68px, 7px);
statusPosition: point(68px, 27px);
photoSize: 40px;
nameFg: groupCallMembersFg;
nameFgChecked: groupCallMembersFg;
statusFg: groupCallMemberInactiveStatus;
statusFgOver: groupCallMemberInactiveStatus;
statusFgActive: groupCallMemberActiveStatus;
}
}
groupCallMembersHeader: 47px;
groupCallMembersMargin: margins(16px, 16px, 16px, 28px);
groupCallAddMember: IconButton(defaultIconButton) {
width: 36px;
height: 36px;
iconPosition: point(3px, 5px);
icon: icon {{ "info_add_member", groupCallMemberInactiveIcon }};
iconOver: icon {{ "info_add_member", groupCallMemberInactiveIcon }};
rippleAreaPosition: point(0px, 0px);
rippleAreaSize: 36px;
ripple: groupCallRipple;
}
groupCallHeaderPosition: point(16px, 16px);
groupCallHeaderLabel: FlatLabel(defaultFlatLabel) {
maxHeight: 18px;
textFg: groupCallMembersFg;
style: TextStyle(defaultTextStyle) {
font: semiboldFont;
linkFont: semiboldFont;
linkFontOver: semiboldFont;
}
}
groupCallAddButtonPosition: point(10px, 7px);
groupCallInactiveButton: IconButton {
width: 36px;
height: 52px;
icon: icon {{ "calls/group_calls_muted", groupCallMemberInactiveIcon }};
iconOver: icon {{ "calls/group_calls_muted", groupCallMemberInactiveIcon }};
iconPosition: point(-1px, -1px);
ripple: groupCallRipple;
rippleAreaPosition: point(0px, 8px);
rippleAreaSize: 36px;
}
groupCallActiveButton: IconButton(groupCallInactiveButton) {
icon: icon {{ "calls/group_calls_unmuted", groupCallMemberActiveIcon }};
iconOver: icon {{ "calls/group_calls_unmuted", groupCallMemberActiveIcon }};
}
groupCallMutedButton: IconButton(groupCallInactiveButton) {
icon: icon {{ "calls/group_calls_muted", groupCallMemberMutedIcon }};
iconOver: icon {{ "calls/group_calls_muted", groupCallMemberMutedIcon }};
}
groupCallMemberButtonSkip: 10px;

View File

@ -0,0 +1,528 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "calls/calls_group_members.h"
#include "calls/calls_group_call.h"
#include "data/data_channel.h"
#include "data/data_user.h"
#include "data/data_changes.h"
#include "data/data_group_call.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/popup_menu.h"
#include "ui/text/text_utilities.h"
#include "ui/effects/ripple_animation.h"
#include "main/main_session.h"
#include "lang/lang_keys.h"
#include "styles/style_calls.h"
namespace Calls {
namespace {
class MembersController final
: public PeerListController
, public base::has_weak_ptr {
public:
explicit MembersController(not_null<GroupCall*> call);
Main::Session &session() const override;
void prepare() override;
void rowClicked(not_null<PeerListRow*> row) override;
void rowActionClicked(not_null<PeerListRow*> row) override;
base::unique_qptr<Ui::PopupMenu> rowContextMenu(
QWidget *parent,
not_null<PeerListRow*> row) override;
void loadMoreRows() override;
private:
[[nodiscard]] std::unique_ptr<PeerListRow> createRow(
not_null<UserData*> user) const;
void prepareRows();
void setupListChangeViewers();
bool appendRow(not_null<UserData*> user);
bool prependRow(not_null<UserData*> user);
bool removeRow(not_null<UserData*> user);
const base::weak_ptr<GroupCall> _call;
const not_null<ChannelData*> _channel;
Ui::BoxPointer _addBox;
rpl::lifetime _lifetime;
};
class Row final : public PeerListRow {
public:
Row(not_null<ChannelData*> channel, not_null<UserData*> user);
enum class State {
Active,
Inactive,
Muted,
};
void addActionRipple(QPoint point, Fn<void()> updateCallback) override;
void stopLastActionRipple() override;
int nameIconWidth() const override {
return 0;
}
QSize actionSize() const override {
return QSize(_st->width, _st->height);
}
QMargins actionMargins() const override {
return QMargins(
0,
0,
st::groupCallMemberButtonSkip,
0);
}
void paintAction(
Painter &p,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) override;
private:
void refreshStatus() override;
[[nodiscard]] static State ComputeState(
not_null<ChannelData*> channel,
not_null<UserData*> user);
[[nodiscard]] static not_null<const style::IconButton*> ComputeIconStyle(
State state);
State _state = State::Inactive;
not_null<const style::IconButton*> _st;
std::unique_ptr<Ui::RippleAnimation> _actionRipple;
};
Row::Row(not_null<ChannelData*> channel, not_null<UserData*> user)
: PeerListRow(user)
, _state(ComputeState(channel, user))
, _st(ComputeIconStyle(_state)) {
refreshStatus();
}
void Row::paintAction(
Painter &p,
int x,
int y,
int outerWidth,
bool selected,
bool actionSelected) {
auto size = actionSize();
if (_actionRipple) {
_actionRipple->paint(
p,
x + _st->rippleAreaPosition.x(),
y + _st->rippleAreaPosition.y(),
outerWidth);
if (_actionRipple->empty()) {
_actionRipple.reset();
}
}
_st->icon.paintInCenter(
p,
style::rtlrect(x, y, size.width(), size.height(), outerWidth));
}
void Row::refreshStatus() {
setCustomStatus([&] {
switch (_state) {
case State::Inactive:
case State::Muted: return "listening";
case State::Active: return "speaking";
}
return "";
}());
}
Row::State Row::ComputeState(
not_null<ChannelData*> channel,
not_null<UserData*> user) {
const auto call = channel->call();
if (!call) {
return State::Inactive;
}
const auto &participants = call->participants();
const auto i = ranges::find(
participants,
user,
&Data::GroupCall::Participant::user);
if (i == end(participants)) {
return State::Inactive;
}
return !i->muted
? State::Active
: i->canSelfUnmute
? State::Inactive
: State::Muted;
}
not_null<const style::IconButton*> Row::ComputeIconStyle(
State state) {
switch (state) {
case State::Inactive: return &st::groupCallInactiveButton;
case State::Active: return &st::groupCallActiveButton;
case State::Muted: return &st::groupCallMutedButton;
}
Unexpected("State in Row::ComputeIconStyle.");
}
void Row::addActionRipple(QPoint point, Fn<void()> updateCallback) {
if (!_actionRipple) {
auto mask = Ui::RippleAnimation::ellipseMask(
QSize(_st->rippleAreaSize, _st->rippleAreaSize));
_actionRipple = std::make_unique<Ui::RippleAnimation>(
_st->ripple,
std::move(mask),
std::move(updateCallback));
}
_actionRipple->add(point - _st->rippleAreaPosition);
}
void Row::stopLastActionRipple() {
if (_actionRipple) {
_actionRipple->lastStop();
}
}
MembersController::MembersController(not_null<GroupCall*> call)
: _call(call)
, _channel(call->channel()) {
setupListChangeViewers();
}
void MembersController::setupListChangeViewers() {
const auto call = _call.get();
const auto channel = call->channel();
channel->session().changes().peerUpdates(
channel,
Data::PeerUpdate::Flag::GroupCall
) | rpl::start_with_next([=] {
prepareRows();
}, _lifetime);
}
Main::Session &MembersController::session() const {
return _call->channel()->session();
}
void MembersController::prepare() {
delegate()->peerListSetSearchMode(PeerListSearchMode::Disabled);
//delegate()->peerListSetTitle(std::move(title));
setDescriptionText(tr::lng_contacts_loading(tr::now));
setSearchNoResultsText(tr::lng_blocked_list_not_found(tr::now));
prepareRows();
delegate()->peerListRefreshRows();
loadMoreRows();
}
void MembersController::prepareRows() {
const auto real = _channel->call();
if (!real) {
return;
}
auto foundSelf = false;
auto changed = false;
const auto &participants = real->participants();
auto count = delegate()->peerListFullRowsCount();
for (auto i = 0; i != count;) {
auto row = delegate()->peerListRowAt(i);
auto user = row->peer()->asUser();
if (user->isSelf()) {
foundSelf = true;
}
const auto contains = ranges::contains(
participants,
not_null{ user },
&Data::GroupCall::Participant::user);
if (contains) {
++i;
} else {
changed = true;
delegate()->peerListRemoveRow(row);
--count;
}
}
if (!foundSelf) {
if (auto row = createRow(_channel->session().user())) {
changed = true;
delegate()->peerListAppendRow(std::move(row));
}
}
for (const auto &participant : participants) {
if (auto row = createRow(participant.user)) {
changed = true;
delegate()->peerListAppendRow(std::move(row));
}
}
if (changed) {
delegate()->peerListRefreshRows();
}
}
void MembersController::loadMoreRows() {
if (const auto call = _call.get()) {
if (const auto real = call->channel()->call()) {
real->requestParticipants();
}
}
}
void MembersController::rowClicked(not_null<PeerListRow*> row) {
Expects(row->peer()->isUser());
const auto user = row->peer()->asUser();
}
void MembersController::rowActionClicked(
not_null<PeerListRow*> row) {
Expects(row->peer()->isUser());
const auto user = row->peer()->asUser();
}
base::unique_qptr<Ui::PopupMenu> MembersController::rowContextMenu(
QWidget *parent,
not_null<PeerListRow*> row) {
Expects(row->peer()->isUser());
const auto user = row->peer()->asUser();
auto result = base::make_unique_q<Ui::PopupMenu>(parent);
//result->addAction( // #TODO calls
// tr::lng_context_view_profile(tr::now),
// crl::guard(this, [=] { _navigation->showPeerInfo(user); }));
return result;
}
bool MembersController::appendRow(not_null<UserData*> user) {
if (delegate()->peerListFindRow(user->id)) {
return false;
}
delegate()->peerListAppendRow(createRow(user));
return true;
}
bool MembersController::prependRow(not_null<UserData*> user) {
if (auto row = delegate()->peerListFindRow(user->id)) {
return false;
}
delegate()->peerListPrependRow(createRow(user));
return true;
}
bool MembersController::removeRow(not_null<UserData*> user) {
if (auto row = delegate()->peerListFindRow(user->id)) {
delegate()->peerListRemoveRow(row);
return true;
}
return false;
}
std::unique_ptr<PeerListRow> MembersController::createRow(
not_null<UserData*> user) const {
return std::make_unique<Row>(_channel, user);
}
} // namespace
GroupMembers::GroupMembers(
QWidget *parent,
not_null<GroupCall*> call)
: RpWidget(parent)
, _call(call)
, _scroll(this, st::defaultSolidScroll)
, _listController(std::make_unique<MembersController>(call)) {
setupHeader(call);
setupList();
setContent(_list);
_listController->setDelegate(static_cast<PeerListDelegate*>(this));
paintRequest(
) | rpl::start_with_next([=](QRect clip) {
QPainter(this).fillRect(clip, st::groupCallMembersBg);
}, lifetime());
}
int GroupMembers::desiredHeight() const {
auto desired = _header ? _header->height() : 0;
auto count = [this] {
if (const auto call = _call.get()) {
if (const auto real = call->channel()->call()) {
return real->fullCount();
}
}
return 0;
}();
desired += qMax(count, _list->fullRowsCount())
* st::groupCallMembersList.item.height;
return qMax(height(), desired);
}
void GroupMembers::setupHeader(not_null<GroupCall*> call) {
_header = object_ptr<Ui::FixedHeightWidget>(
this,
st::groupCallMembersHeader);
auto parent = _header.data();
_titleWrap = Ui::CreateChild<Ui::RpWidget>(parent);
_title = setupTitle(call);
_addMember = Ui::CreateChild<Ui::IconButton>(
parent,
st::groupCallAddMember);
setupButtons();
widthValue(
) | rpl::start_with_next([this](int width) {
_header->resizeToWidth(width);
}, _header->lifetime());
}
object_ptr<Ui::FlatLabel> GroupMembers::setupTitle(
not_null<GroupCall*> call) {
const auto channel = call->channel();
auto count = channel->session().changes().peerFlagsValue(
channel,
Data::PeerUpdate::Flag::GroupCall
) | rpl::map([=] {
const auto call = channel->call();
return std::max(call ? call->fullCount() : 0, 1);
});
auto result = object_ptr<Ui::FlatLabel>(
_titleWrap,
tr::lng_chat_status_members(
lt_count_decimal,
std::move(count) | tr::to_count(),
Ui::Text::Upper
),
st::groupCallHeaderLabel);
result->setAttribute(Qt::WA_TransparentForMouseEvents);
return result;
}
void GroupMembers::setupButtons() {
using namespace rpl::mappers;
_addMember->showOn(rpl::single(true));
_addMember->addClickHandler([=] { // TODO throttle(ripple duration)
addMember();
});
}
void GroupMembers::setupList() {
auto topSkip = _header ? _header->height() : 0;
_list = _scroll->setOwnedWidget(object_ptr<ListWidget>(
this,
_listController.get(),
st::groupCallMembersList));
sizeValue(
) | rpl::start_with_next([=](QSize size) {
_scroll->setGeometry(0, topSkip, size.width(), size.height() - topSkip);
_list->resizeToWidth(size.width());
}, _list->lifetime());
_list->heightValue(
) | rpl::start_with_next([=](int listHeight) {
auto newHeight = (listHeight > 0)
? (topSkip + listHeight)
: 0;
resize(width(), newHeight);
}, _list->lifetime());
_list->moveToLeft(0, topSkip);
_list->show();
}
void GroupMembers::resizeEvent(QResizeEvent *e) {
if (_header) {
updateHeaderControlsGeometry(width());
}
}
void GroupMembers::updateHeaderControlsGeometry(int newWidth) {
auto availableWidth = newWidth
- st::groupCallAddButtonPosition.x();
_addMember->moveToLeft(
availableWidth - _addMember->width(),
st::groupCallAddButtonPosition.y(),
newWidth);
if (!_addMember->isHidden()) {
availableWidth -= _addMember->width();
}
_titleWrap->resize(
availableWidth - _addMember->width() - st::groupCallHeaderPosition.x(),
_title->height());
_titleWrap->moveToLeft(
st::groupCallHeaderPosition.x(),
st::groupCallHeaderPosition.y(),
newWidth);
_titleWrap->setAttribute(Qt::WA_TransparentForMouseEvents);
_title->resizeToWidth(_titleWrap->width());
_title->moveToLeft(0, 0);
}
void GroupMembers::addMember() {
// #TODO calls
}
void GroupMembers::visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) {
setChildVisibleTopBottom(_list, visibleTop, visibleBottom);
}
void GroupMembers::peerListSetTitle(rpl::producer<QString> title) {
}
void GroupMembers::peerListSetAdditionalTitle(rpl::producer<QString> title) {
}
bool GroupMembers::peerListIsRowChecked(not_null<PeerListRow*> row) {
return false;
}
void GroupMembers::peerListScrollToTop() {
}
int GroupMembers::peerListSelectedRowsCount() {
return 0;
}
std::vector<not_null<PeerData*>> GroupMembers::peerListCollectSelectedRows() {
return {};
}
void GroupMembers::peerListAddSelectedPeerInBunch(not_null<PeerData*> peer) {
Unexpected("Item selection in Info::Profile::Members.");
}
void GroupMembers::peerListAddSelectedRowInBunch(not_null<PeerListRow*> row) {
Unexpected("Item selection in Info::Profile::Members.");
}
void GroupMembers::peerListFinishSelectedRowsBunch() {
}
void GroupMembers::peerListSetDescription(
object_ptr<Ui::FlatLabel> description) {
description.destroy();
}
} // namespace Calls

View File

@ -0,0 +1,76 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "boxes/peer_list_box.h"
namespace Ui {
class ScrollArea;
} // namespace Ui
namespace Calls {
class GroupCall;
class GroupMembers final
: public Ui::RpWidget
, private PeerListContentDelegate {
public:
GroupMembers(
QWidget *parent,
not_null<GroupCall*> call);
int desiredHeight() const;
private:
using ListWidget = PeerListContent;
void visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) override;
void resizeEvent(QResizeEvent *e) override;
// PeerListContentDelegate interface.
void peerListSetTitle(rpl::producer<QString> title) override;
void peerListSetAdditionalTitle(rpl::producer<QString> title) override;
bool peerListIsRowChecked(not_null<PeerListRow*> row) override;
int peerListSelectedRowsCount() override;
void peerListScrollToTop() override;
std::vector<not_null<PeerData*>> peerListCollectSelectedRows() override;
void peerListAddSelectedPeerInBunch(
not_null<PeerData*> peer) override;
void peerListAddSelectedRowInBunch(
not_null<PeerListRow*> row) override;
void peerListFinishSelectedRowsBunch() override;
void peerListSetDescription(
object_ptr<Ui::FlatLabel> description) override;
void setupHeader(not_null<GroupCall*> call);
object_ptr<Ui::FlatLabel> setupTitle(not_null<GroupCall*> call);
void setupList();
void setupButtons();
void addMember();
void showMembersWithSearch(bool withSearch);
void updateHeaderControlsGeometry(int newWidth);
base::weak_ptr<GroupCall> _call;
object_ptr<Ui::ScrollArea> _scroll;
std::unique_ptr<PeerListController> _listController;
object_ptr<Ui::RpWidget> _header = { nullptr };
ListWidget *_list = { nullptr };
Ui::RpWidget *_titleWrap = nullptr;
Ui::FlatLabel *_title = nullptr;
Ui::IconButton *_addMember = nullptr;
};
} // namespace Calls

View File

@ -7,42 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "calls/calls_group_panel.h"
#include "data/data_photo.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/data_file_origin.h"
#include "data/data_photo_media.h"
#include "data/data_cloud_file.h"
#include "data/data_changes.h"
#include "calls/calls_emoji_fingerprint.h"
#include "calls/calls_signal_bars.h"
#include "calls/calls_userpic.h"
#include "calls/calls_video_bubble.h"
#include "calls/calls_group_members.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/window.h"
#include "ui/effects/ripple_animation.h"
#include "ui/image/image.h"
#include "ui/text/format_values.h"
#include "ui/wrap/fade_wrap.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/platform/ui_platform_utility.h"
#include "ui/toast/toast.h"
#include "ui/empty_userpic.h"
#include "ui/emoji_config.h"
#include "core/application.h"
#include "mainwindow.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "apiwrap.h"
#include "platform/platform_specific.h"
#include "base/platform/base_platform_info.h"
#include "window/main_window.h"
#include "base/event_filter.h"
#include "app.h"
#include "webrtc/webrtc_video_track.h"
#include "styles/style_calls.h"
#include "styles/style_chat.h"
#ifdef Q_OS_WIN
#include "ui/platform/win/ui_window_title_win.h"
@ -246,9 +219,9 @@ GroupPanel::GroupPanel(not_null<GroupCall*> call)
#ifdef Q_OS_WIN
, _controls(std::make_unique<Ui::Platform::TitleControls>(
_window.get(),
st::callTitle,
[=](bool maximized) { toggleFullScreen(maximized); }))
st::callTitle))
#endif // Q_OS_WIN
, _members(widget(), call)
, _settings(widget(), st::callCancel)
, _hangup(widget(), st::callHangup)
, _mute(widget(), st::callMicrophoneMute, &st::callMicrophoneUnmute) {
@ -262,6 +235,9 @@ GroupPanel::GroupPanel(not_null<GroupCall*> call)
GroupPanel::~GroupPanel() = default;
void GroupPanel::showAndActivate() {
if (_window->isHidden()) {
_window->show();
}
_window->raise();
_window->setWindowState(_window->windowState() | Qt::WindowActive);
_window->activateWindow();
@ -276,17 +252,13 @@ void GroupPanel::initWindow() {
_window->setTitle(u" "_q);
_window->setTitleStyle(st::callTitle);
_window->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) {
if (e->type() == QEvent::Close) {
handleClose();
} else if (e->type() == QEvent::KeyPress) {
if ((static_cast<QKeyEvent*>(e.get())->key() == Qt::Key_Escape)
&& _window->isFullScreen()) {
_window->showNormal();
}
base::install_event_filter(_window.get(), [=](not_null<QEvent*> e) {
if (e->type() == QEvent::Close && handleClose()) {
e->ignore();
return base::EventFilterResult::Cancel;
}
}, _window->lifetime());
return base::EventFilterResult::Continue;
});
_window->setBodyTitleArea([=](QPoint widgetPoint) {
using Flag = Ui::WindowTitleHitTestFlag;
@ -301,31 +273,8 @@ void GroupPanel::initWindow() {
const auto inControls = false;
return inControls
? Flag::None
: (Flag::Move | Flag::FullScreen);
: (Flag::Move | Flag::Maximize);
});
#ifdef Q_OS_WIN
// On Windows we replace snap-to-top maximizing with fullscreen.
//
// We have to switch first to showNormal, so that showFullScreen
// will remember correct normal window geometry and next showNormal
// will show it instead of a moving maximized window.
//
// We have to do it in InvokeQueued, otherwise it still captures
// the maximized window geometry and saves it.
//
// I couldn't find a less glitchy way to do that *sigh*.
const auto object = _window->windowHandle();
const auto signal = &QWindow::windowStateChanged;
QObject::connect(object, signal, [=](Qt::WindowState state) {
if (state == Qt::WindowMaximized) {
InvokeQueued(object, [=] {
_window->showNormal();
_window->showFullScreen();
});
}
});
#endif // Q_OS_WIN
}
void GroupPanel::initWidget() {
@ -382,6 +331,11 @@ void GroupPanel::initWithCall(GroupCall *call) {
) | rpl::start_with_next([=](State state) {
stateChanged(state);
}, _callLifetime);
_members->desiredHeightValue(
) | rpl::start_with_next([=] {
updateControlsGeometry();
}, _members->lifetime());
}
void GroupPanel::initLayout() {
@ -412,22 +366,33 @@ void GroupPanel::initGeometry() {
updateControlsGeometry();
}
void GroupPanel::toggleFullScreen(bool fullscreen) {
if (fullscreen) {
_window->showFullScreen();
} else {
_window->showNormal();
}
}
void GroupPanel::updateControlsGeometry() {
if (widget()->size().isEmpty()) {
return;
}
const auto top = widget()->height() - 2 * _mute->height();
_mute->move((widget()->width() - _mute->width()) / 2, top);
_settings->moveToLeft(_settings->width(), top);
_hangup->moveToRight(_settings->width(), top);
const auto desiredHeight = _members->desiredHeight();
const auto membersWidth = widget()->width()
- st::groupCallMembersMargin.left()
- st::groupCallMembersMargin.right();
const auto muteTop = widget()->height() - 2 * _mute->height();
const auto buttonsTop = muteTop;
#ifdef Q_OS_WIN
const auto membersTop = st::callTitleButton.height
+ st::groupCallMembersMargin.top() / 2;
#else // Q_OS_WIN
const auto membersTop = st::groupCallMembersMargin.top();
#endif // Q_OS_WIN
const auto availableHeight = buttonsTop
- membersTop
- st::groupCallMembersMargin.bottom();
_members->setGeometry(
st::groupCallMembersMargin.left(),
membersTop,
membersWidth,
std::min(desiredHeight, availableHeight));
_mute->move((widget()->width() - _mute->width()) / 2, muteTop);
_settings->moveToLeft(_settings->width(), buttonsTop);
_hangup->moveToRight(_settings->width(), buttonsTop);
}
void GroupPanel::paint(QRect clip) {
@ -435,14 +400,16 @@ void GroupPanel::paint(QRect clip) {
auto region = QRegion(clip);
for (const auto rect : region) {
p.fillRect(rect, st::callBgOpaque);
p.fillRect(rect, st::groupCallBg);
}
}
void GroupPanel::handleClose() {
bool GroupPanel::handleClose() {
if (_call) {
_call->hangup();
_window->hide();
return true;
}
return false;
}
not_null<Ui::RpWidget*> GroupPanel::widget() const {

View File

@ -29,6 +29,7 @@ class FadeWrap;
template <typename Widget>
class PaddingWrap;
class Window;
class ScrollArea;
namespace Platform {
class TitleControls;
} // namespace Platform
@ -44,6 +45,8 @@ namespace Calls {
class Userpic;
class SignalBars;
class GroupMembers;
class GroupPanel final {
public:
GroupPanel(not_null<GroupCall*> call);
@ -67,14 +70,11 @@ private:
void initLayout();
void initGeometry();
void handleClose();
bool handleClose();
void updateControlsGeometry();
void stateChanged(State state);
void showControls();
void startDurationUpdateTimer(crl::time currentDuration);
void toggleFullScreen(bool fullscreen);
GroupCall *_call = nullptr;
not_null<ChannelData*> _channel;
@ -87,6 +87,8 @@ private:
rpl::lifetime _callLifetime;
object_ptr<GroupMembers> _members;
object_ptr<Button> _settings;
object_ptr<Button> _hangup;
object_ptr<Button> _mute;

View File

@ -35,7 +35,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::content() const {
if (!call || (current && current->channel() == channel)) {
return { .shown = false };
} else if (!call->fullCount() && !call->participantsLoaded()) {
call->requestParticipants();
call->reload();
}
return { .count = call->fullCount(), .shown = true };
});

View File

@ -517,22 +517,22 @@ historyUnreadBarFont: semiboldFont;
historyForwardChooseMargins: margins(30px, 10px, 30px, 10px);
historyForwardChooseFont: font(16px);
historyCallArrowIn: icon {{ "call_arrow_in", historyCallArrowInFg }};
historyCallArrowInSelected: icon {{ "call_arrow_in", historyCallArrowInFgSelected }};
historyCallArrowMissedIn: icon {{ "call_arrow_in", historyCallArrowMissedInFg }};
historyCallArrowMissedInSelected: icon {{ "call_arrow_in", historyCallArrowMissedInFgSelected }};
historyCallArrowOut: icon {{ "call_arrow_out", historyCallArrowOutFg }};
historyCallArrowOutSelected: icon {{ "call_arrow_out", historyCallArrowOutFgSelected }};
historyCallArrowIn: icon {{ "calls/call_arrow_in", historyCallArrowInFg }};
historyCallArrowInSelected: icon {{ "calls/call_arrow_in", historyCallArrowInFgSelected }};
historyCallArrowMissedIn: icon {{ "calls/call_arrow_in", historyCallArrowMissedInFg }};
historyCallArrowMissedInSelected: icon {{ "calls/call_arrow_in", historyCallArrowMissedInFgSelected }};
historyCallArrowOut: icon {{ "calls/call_arrow_out", historyCallArrowOutFg }};
historyCallArrowOutSelected: icon {{ "calls/call_arrow_out", historyCallArrowOutFgSelected }};
historyCallWidth: 240px;
historyCallHeight: 56px;
historyCallInIcon: icon {{ "call_answer", msgFileInBg }};
historyCallInIconSelected: icon {{ "call_answer", msgFileInBgSelected }};
historyCallOutIcon: icon {{ "call_answer", msgFileOutBg }};
historyCallOutIconSelected: icon {{ "call_answer", msgFileOutBgSelected }};
historyCallCameraInIcon: icon {{ "call_camera_active", msgFileInBg }};
historyCallCameraInIconSelected: icon {{ "call_camera_active", msgFileInBgSelected }};
historyCallCameraOutIcon: icon {{ "call_camera_active", msgFileOutBg }};
historyCallCameraOutIconSelected: icon {{ "call_camera_active", msgFileOutBgSelected }};
historyCallInIcon: icon {{ "calls/call_answer", msgFileInBg }};
historyCallInIconSelected: icon {{ "calls/call_answer", msgFileInBgSelected }};
historyCallOutIcon: icon {{ "calls/call_answer", msgFileOutBg }};
historyCallOutIconSelected: icon {{ "calls/call_answer", msgFileOutBgSelected }};
historyCallCameraInIcon: icon {{ "calls/call_camera_active", msgFileInBg }};
historyCallCameraInIconSelected: icon {{ "calls/call_camera_active", msgFileInBgSelected }};
historyCallCameraOutIcon: icon {{ "calls/call_camera_active", msgFileOutBg }};
historyCallCameraOutIconSelected: icon {{ "calls/call_camera_active", msgFileOutBgSelected }};
historyCallIconPosition: point(12px, 10px);
historyCallLeft: 16px;
historyCallTop: 9px;

@ -1 +1 @@
Subproject commit f06346fbf03900c278e1d59717e1387bffc03f39
Subproject commit e73bae12e26811f70adff5adfafbdb2548e02cd0