Start group call members list.
|
@ -266,6 +266,8 @@ PRIVATE
|
||||||
calls/calls_call.h
|
calls/calls_call.h
|
||||||
calls/calls_group_call.cpp
|
calls/calls_group_call.cpp
|
||||||
calls/calls_group_call.h
|
calls/calls_group_call.h
|
||||||
|
calls/calls_group_members.cpp
|
||||||
|
calls/calls_group_members.h
|
||||||
calls/calls_group_panel.cpp
|
calls/calls_group_panel.cpp
|
||||||
calls/calls_group_panel.h
|
calls/calls_group_panel.h
|
||||||
calls/calls_emoji_fingerprint.cpp
|
calls/calls_emoji_fingerprint.cpp
|
||||||
|
|
Before Width: | Height: | Size: 595 B After Width: | Height: | Size: 595 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 209 B After Width: | Height: | Size: 209 B |
Before Width: | Height: | Size: 306 B After Width: | Height: | Size: 306 B |
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 449 B |
Before Width: | Height: | Size: 211 B After Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 298 B After Width: | Height: | Size: 298 B |
Before Width: | Height: | Size: 443 B After Width: | Height: | Size: 443 B |
Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 377 B |
Before Width: | Height: | Size: 733 B After Width: | Height: | Size: 733 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 727 B After Width: | Height: | Size: 727 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 214 B After Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 426 B After Width: | Height: | Size: 426 B |
Before Width: | Height: | Size: 912 B After Width: | Height: | Size: 912 B |
Before Width: | Height: | Size: 460 B After Width: | Height: | Size: 460 B |
Before Width: | Height: | Size: 970 B After Width: | Height: | Size: 970 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 666 B After Width: | Height: | Size: 666 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 560 B After Width: | Height: | Size: 560 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 489 B After Width: | Height: | Size: 489 B |
Before Width: | Height: | Size: 1,002 B After Width: | Height: | Size: 1,002 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 744 B After Width: | Height: | Size: 744 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 100 B After Width: | Height: | Size: 100 B |
Before Width: | Height: | Size: 125 B After Width: | Height: | Size: 125 B |
Before Width: | Height: | Size: 139 B After Width: | Height: | Size: 139 B |
Before Width: | Height: | Size: 103 B After Width: | Height: | Size: 103 B |
Before Width: | Height: | Size: 127 B After Width: | Height: | Size: 127 B |
Before Width: | Height: | Size: 141 B After Width: | Height: | Size: 141 B |
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 559 B After Width: | Height: | Size: 559 B |
Before Width: | Height: | Size: 927 B After Width: | Height: | Size: 927 B |
Before Width: | Height: | Size: 305 B After Width: | Height: | Size: 305 B |
Before Width: | Height: | Size: 524 B After Width: | Height: | Size: 524 B |
Before Width: | Height: | Size: 820 B After Width: | Height: | Size: 820 B |
Before Width: | Height: | Size: 385 B After Width: | Height: | Size: 385 B |
Before Width: | Height: | Size: 873 B After Width: | Height: | Size: 873 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 230 B After Width: | Height: | Size: 230 B |
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 393 B |
Before Width: | Height: | Size: 616 B After Width: | Height: | Size: 616 B |
Before Width: | Height: | Size: 333 B After Width: | Height: | Size: 333 B |
Before Width: | Height: | Size: 552 B After Width: | Height: | Size: 552 B |
Before Width: | Height: | Size: 889 B After Width: | Height: | Size: 889 B |
Before Width: | Height: | Size: 173 B After Width: | Height: | Size: 173 B |
Before Width: | Height: | Size: 304 B After Width: | Height: | Size: 304 B |
Before Width: | Height: | Size: 545 B After Width: | Height: | Size: 545 B |
Before Width: | Height: | Size: 228 B After Width: | Height: | Size: 228 B |
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
Before Width: | Height: | Size: 661 B After Width: | Height: | Size: 661 B |
Before Width: | Height: | Size: 637 B After Width: | Height: | Size: 637 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 545 B After Width: | Height: | Size: 545 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 290 B |
Before Width: | Height: | Size: 499 B After Width: | Height: | Size: 499 B |
Before Width: | Height: | Size: 846 B After Width: | Height: | Size: 846 B |
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
Before Width: | Height: | Size: 715 B After Width: | Height: | Size: 715 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
BIN
Telegram/Resources/icons/calls/group_calls_muted.png
Normal file
After Width: | Height: | Size: 718 B |
BIN
Telegram/Resources/icons/calls/group_calls_muted@2x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/calls/group_calls_muted@3x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
Telegram/Resources/icons/calls/group_calls_unmuted.png
Normal file
After Width: | Height: | Size: 599 B |
BIN
Telegram/Resources/icons/calls/group_calls_unmuted@2x.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
Telegram/Resources/icons/calls/group_calls_unmuted@3x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
|
@ -219,7 +219,6 @@ contactsPhotoCheckIcon: defaultPeerListCheckIcon;
|
||||||
contactsPhotoCheck: defaultPeerListCheck;
|
contactsPhotoCheck: defaultPeerListCheck;
|
||||||
contactsPhotoCheckbox: defaultPeerListCheckbox;
|
contactsPhotoCheckbox: defaultPeerListCheckbox;
|
||||||
contactsPhotoDisabledCheckFg: menuIconFg;
|
contactsPhotoDisabledCheckFg: menuIconFg;
|
||||||
contactsNameCheckedFg: windowActiveTextFg;
|
|
||||||
contactsRipple: defaultRippleAnimation;
|
contactsRipple: defaultRippleAnimation;
|
||||||
|
|
||||||
contactsMarginTop: 4px;
|
contactsMarginTop: 4px;
|
||||||
|
|
|
@ -1283,7 +1283,7 @@ crl::time PeerListContent::paintRow(
|
||||||
selected);
|
selected);
|
||||||
}
|
}
|
||||||
auto nameCheckedRatio = row->disabled() ? 0. : row->checkedRatio();
|
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());
|
name.drawLeftElided(p, namex, _st.item.namePosition.y(), namew, width());
|
||||||
|
|
||||||
if (!actionSize.isEmpty()) {
|
if (!actionSize.isEmpty()) {
|
||||||
|
|
|
@ -135,7 +135,6 @@ private:
|
||||||
// Viewing admins, banned or restricted users list with search.
|
// Viewing admins, banned or restricted users list with search.
|
||||||
class ParticipantsBoxController
|
class ParticipantsBoxController
|
||||||
: public PeerListController
|
: public PeerListController
|
||||||
, private base::Subscriber
|
|
||||||
, public base::has_weak_ptr {
|
, public base::has_weak_ptr {
|
||||||
public:
|
public:
|
||||||
using Role = ParticipantsRole;
|
using Role = ParticipantsRole;
|
||||||
|
|
|
@ -22,14 +22,14 @@ CallSignalBars {
|
||||||
|
|
||||||
callRadius: 6px;
|
callRadius: 6px;
|
||||||
callShadow: Shadow {
|
callShadow: Shadow {
|
||||||
left: icon {{ "call_shadow_left", windowShadowFg }};
|
left: icon {{ "calls/call_shadow_left", windowShadowFg }};
|
||||||
topLeft: icon {{ "call_shadow_top_left", windowShadowFg }};
|
topLeft: icon {{ "calls/call_shadow_top_left", windowShadowFg }};
|
||||||
top: icon {{ "call_shadow_top", windowShadowFg }};
|
top: icon {{ "calls/call_shadow_top", windowShadowFg }};
|
||||||
topRight: icon {{ "call_shadow_top_left-flip_horizontal", windowShadowFg }};
|
topRight: icon {{ "calls/call_shadow_top_left-flip_horizontal", windowShadowFg }};
|
||||||
right: icon {{ "call_shadow_left-flip_horizontal", windowShadowFg }};
|
right: icon {{ "calls/call_shadow_left-flip_horizontal", windowShadowFg }};
|
||||||
bottomRight: icon {{ "call_shadow_top_left-flip_vertical-flip_horizontal", windowShadowFg }};
|
bottomRight: icon {{ "calls/call_shadow_top_left-flip_vertical-flip_horizontal", windowShadowFg }};
|
||||||
bottom: icon {{ "call_shadow_top-flip_vertical", windowShadowFg }};
|
bottom: icon {{ "calls/call_shadow_top-flip_vertical", windowShadowFg }};
|
||||||
bottomLeft: icon {{ "call_shadow_top_left-flip_vertical", windowShadowFg }};
|
bottomLeft: icon {{ "calls/call_shadow_top_left-flip_vertical", windowShadowFg }};
|
||||||
extend: margins(9px, 8px, 9px, 10px);
|
extend: margins(9px, 8px, 9px, 10px);
|
||||||
fallback: windowShadowFgFallback;
|
fallback: windowShadowFgFallback;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ callBodyWithPreview: CallBodyLayout {
|
||||||
muteSize: 0px;
|
muteSize: 0px;
|
||||||
mutePosition: point(90px, 84px);
|
mutePosition: point(90px, 84px);
|
||||||
}
|
}
|
||||||
callMutedPeerIcon: icon {{ "calls_mute_userpic", callIconFg }};
|
callMutedPeerIcon: icon {{ "calls/calls_mute_userpic", callIconFg }};
|
||||||
|
|
||||||
callOutgoingPreviewMin: size(360px, 120px);
|
callOutgoingPreviewMin: size(360px, 120px);
|
||||||
callOutgoingPreview: size(540px, 180px); // default, for height == callHeight.
|
callOutgoingPreview: size(540px, 180px); // default, for height == callHeight.
|
||||||
|
@ -89,7 +89,7 @@ callSignalBarsPadding: margins(8px, 9px, 11px, 5px);
|
||||||
callFingerprintTop: 8px;
|
callFingerprintTop: 8px;
|
||||||
callFingerprintBottom: -16px;
|
callFingerprintBottom: -16px;
|
||||||
|
|
||||||
callTooltipMutedIcon: icon{{ "calls_mute_tooltip", videoPlayIconFg }};
|
callTooltipMutedIcon: icon{{ "calls/calls_mute_tooltip", videoPlayIconFg }};
|
||||||
callTooltipMutedIconPosition: point(10px, 5px);
|
callTooltipMutedIconPosition: point(10px, 5px);
|
||||||
callTooltipPadding: margins(41px, 7px, 15px, 8px);
|
callTooltipPadding: margins(41px, 7px, 15px, 8px);
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ callButtonLabel: FlatLabel(defaultFlatLabel) {
|
||||||
|
|
||||||
callAnswer: CallButton {
|
callAnswer: CallButton {
|
||||||
button: IconButton(callButton) {
|
button: IconButton(callButton) {
|
||||||
icon: icon {{ "call_answer", callIconFg }};
|
icon: icon {{ "calls/call_answer", callIconFg }};
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: callAnswerRipple;
|
color: callAnswerRipple;
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ callAnswer: CallButton {
|
||||||
}
|
}
|
||||||
callHangup: CallButton {
|
callHangup: CallButton {
|
||||||
button: IconButton(callButton) {
|
button: IconButton(callButton) {
|
||||||
icon: icon {{ "call_discard", callIconFg }};
|
icon: icon {{ "calls/call_discard", callIconFg }};
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: callHangupRipple;
|
color: callHangupRipple;
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ callHangup: CallButton {
|
||||||
}
|
}
|
||||||
callCancel: CallButton {
|
callCancel: CallButton {
|
||||||
button: IconButton(callButton) {
|
button: IconButton(callButton) {
|
||||||
icon: icon {{ "call_cancel", callIconFgActive }};
|
icon: icon {{ "calls/call_cancel", callIconFgActive }};
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: callIconActiveRipple;
|
color: callIconActiveRipple;
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,7 @@ callCancel: CallButton {
|
||||||
}
|
}
|
||||||
callMicrophoneMute: CallButton {
|
callMicrophoneMute: CallButton {
|
||||||
button: IconButton(callButton) {
|
button: IconButton(callButton) {
|
||||||
icon: icon {{ "call_record_active", callIconFg }};
|
icon: icon {{ "calls/call_record_active", callIconFg }};
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: callMuteRipple;
|
color: callMuteRipple;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ callMicrophoneMute: CallButton {
|
||||||
}
|
}
|
||||||
callMicrophoneUnmute: CallButton(callMicrophoneMute) {
|
callMicrophoneUnmute: CallButton(callMicrophoneMute) {
|
||||||
button: IconButton(callButton) {
|
button: IconButton(callButton) {
|
||||||
icon: icon {{ "call_record_muted", callIconFgActive }};
|
icon: icon {{ "calls/call_record_muted", callIconFgActive }};
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: callIconActiveRipple;
|
color: callIconActiveRipple;
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ callMicrophoneUnmute: CallButton(callMicrophoneMute) {
|
||||||
}
|
}
|
||||||
callCameraMute: CallButton(callMicrophoneMute) {
|
callCameraMute: CallButton(callMicrophoneMute) {
|
||||||
button: IconButton(callButton) {
|
button: IconButton(callButton) {
|
||||||
icon: icon {{ "call_camera_active", callIconFg }};
|
icon: icon {{ "calls/call_camera_active", callIconFg }};
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: callMuteRipple;
|
color: callMuteRipple;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ callCameraMute: CallButton(callMicrophoneMute) {
|
||||||
}
|
}
|
||||||
callCameraUnmute: CallButton(callMicrophoneUnmute) {
|
callCameraUnmute: CallButton(callMicrophoneUnmute) {
|
||||||
button: IconButton(callButton) {
|
button: IconButton(callButton) {
|
||||||
icon: icon {{ "call_camera_muted", callIconFgActive }};
|
icon: icon {{ "calls/call_camera_muted", callIconFgActive }};
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: callIconActiveRipple;
|
color: callIconActiveRipple;
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ callBarMuteToggle: IconButton {
|
||||||
width: 41px;
|
width: 41px;
|
||||||
height: 38px;
|
height: 38px;
|
||||||
|
|
||||||
icon: icon {{ "call_record_active", callBarFg }};
|
icon: icon {{ "calls/call_record_active", callBarFg }};
|
||||||
iconPosition: point(3px, 2px);
|
iconPosition: point(3px, 2px);
|
||||||
|
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
@ -232,11 +232,11 @@ callBarMuteToggle: IconButton {
|
||||||
rippleAreaPosition: point(5px, 3px);
|
rippleAreaPosition: point(5px, 3px);
|
||||||
rippleAreaSize: 32px;
|
rippleAreaSize: 32px;
|
||||||
}
|
}
|
||||||
callBarUnmuteIcon: icon {{ "call_record_muted", callBarFg }};
|
callBarUnmuteIcon: icon {{ "calls/call_record_muted", callBarFg }};
|
||||||
callBarRightSkip: 12px;
|
callBarRightSkip: 12px;
|
||||||
callBarSkip: 10px;
|
callBarSkip: 10px;
|
||||||
callBarHangup: IconButton(callBarMuteToggle) {
|
callBarHangup: IconButton(callBarMuteToggle) {
|
||||||
icon: icon {{ "call_discard", callBarFg }};
|
icon: icon {{ "calls/call_discard", callBarFg }};
|
||||||
iconPosition: point(3px, 1px);
|
iconPosition: point(3px, 1px);
|
||||||
}
|
}
|
||||||
callBarLabel: LabelSimple(defaultLabelSimple) {
|
callBarLabel: LabelSimple(defaultLabelSimple) {
|
||||||
|
@ -254,16 +254,16 @@ callBarInfoLabel: FlatLabel(defaultFlatLabel) {
|
||||||
callBarLabelTop: 10px;
|
callBarLabelTop: 10px;
|
||||||
|
|
||||||
callArrowPosition: point(-2px, 1px);
|
callArrowPosition: point(-2px, 1px);
|
||||||
callArrowIn: icon {{ "call_arrow_in", callArrowFg }};
|
callArrowIn: icon {{ "calls/call_arrow_in", callArrowFg }};
|
||||||
callArrowOut: icon {{ "call_arrow_out", callArrowFg }};
|
callArrowOut: icon {{ "calls/call_arrow_out", callArrowFg }};
|
||||||
callArrowMissed: icon {{ "call_arrow_in", callArrowMissedFg }};
|
callArrowMissed: icon {{ "calls/call_arrow_in", callArrowMissedFg }};
|
||||||
callArrowSkip: 4px;
|
callArrowSkip: 4px;
|
||||||
callReDial: IconButton {
|
callReDial: IconButton {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
|
|
||||||
icon: icon {{ "call_answer", menuIconFg }};
|
icon: icon {{ "calls/call_answer", menuIconFg }};
|
||||||
iconOver: icon {{ "call_answer", menuIconFgOver }};
|
iconOver: icon {{ "calls/call_answer", menuIconFgOver }};
|
||||||
iconPosition: point(-1px, -1px);
|
iconPosition: point(-1px, -1px);
|
||||||
|
|
||||||
ripple: defaultRippleAnimation;
|
ripple: defaultRippleAnimation;
|
||||||
|
@ -272,8 +272,8 @@ callReDial: IconButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
callCameraReDial: IconButton(callReDial) {
|
callCameraReDial: IconButton(callReDial) {
|
||||||
icon: icon {{ "call_camera_active", menuIconFg }};
|
icon: icon {{ "calls/call_camera_active", menuIconFg }};
|
||||||
iconOver: icon {{ "call_camera_active", menuIconFgOver }};
|
iconOver: icon {{ "calls/call_camera_active", menuIconFgOver }};
|
||||||
}
|
}
|
||||||
|
|
||||||
callRatingPadding: margins(24px, 12px, 24px, 0px);
|
callRatingPadding: margins(24px, 12px, 24px, 0px);
|
||||||
|
@ -281,7 +281,7 @@ callRatingStar: IconButton {
|
||||||
width: 36px;
|
width: 36px;
|
||||||
height: 36px;
|
height: 36px;
|
||||||
|
|
||||||
icon: icon {{ "call_rating", windowSubTextFg }};
|
icon: icon {{ "calls/call_rating", windowSubTextFg }};
|
||||||
iconPosition: point(-1px, -1px);
|
iconPosition: point(-1px, -1px);
|
||||||
|
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
@ -290,7 +290,7 @@ callRatingStar: IconButton {
|
||||||
rippleAreaPosition: point(0px, 0px);
|
rippleAreaPosition: point(0px, 0px);
|
||||||
rippleAreaSize: 36px;
|
rippleAreaSize: 36px;
|
||||||
}
|
}
|
||||||
callRatingStarFilled: icon {{ "call_rating_filled", lightButtonFg }};
|
callRatingStarFilled: icon {{ "calls/call_rating_filled", lightButtonFg }};
|
||||||
callRatingStarTop: 4px;
|
callRatingStarTop: 4px;
|
||||||
callRatingComment: InputField(defaultInputField) {
|
callRatingComment: InputField(defaultInputField) {
|
||||||
textMargins: margins(1px, 26px, 1px, 4px);
|
textMargins: margins(1px, 26px, 1px, 4px);
|
||||||
|
@ -327,43 +327,43 @@ callTitleButton: IconButton {
|
||||||
iconPosition: point(0px, 0px);
|
iconPosition: point(0px, 0px);
|
||||||
}
|
}
|
||||||
callTitleMinimizeIcon: icon {
|
callTitleMinimizeIcon: icon {
|
||||||
{ "calls_minimize_shadow", windowShadowFg },
|
{ "calls/calls_minimize_shadow", windowShadowFg },
|
||||||
{ "calls_minimize_main", callNameFg },
|
{ "calls/calls_minimize_main", callNameFg },
|
||||||
};
|
};
|
||||||
callTitleMinimizeIconOver: icon {
|
callTitleMinimizeIconOver: icon {
|
||||||
{ size(34px, 30px), callBgButton },
|
{ size(34px, 30px), callBgButton },
|
||||||
{ size(34px, 30px), callMuteRipple },
|
{ size(34px, 30px), callMuteRipple },
|
||||||
{ "calls_minimize_shadow", windowShadowFg },
|
{ "calls/calls_minimize_shadow", windowShadowFg },
|
||||||
{ "calls_minimize_main", callNameFg },
|
{ "calls/calls_minimize_main", callNameFg },
|
||||||
};
|
};
|
||||||
callTitleMaximizeIcon: icon {
|
callTitleMaximizeIcon: icon {
|
||||||
{ "calls_maximize_shadow", windowShadowFg },
|
{ "calls/calls_maximize_shadow", windowShadowFg },
|
||||||
{ "calls_maximize_main", callNameFg },
|
{ "calls/calls_maximize_main", callNameFg },
|
||||||
};
|
};
|
||||||
callTitleMaximizeIconOver: icon {
|
callTitleMaximizeIconOver: icon {
|
||||||
{ size(34px, 30px), callBgButton },
|
{ size(34px, 30px), callBgButton },
|
||||||
{ size(34px, 30px), callMuteRipple },
|
{ size(34px, 30px), callMuteRipple },
|
||||||
{ "calls_maximize_shadow", windowShadowFg },
|
{ "calls/calls_maximize_shadow", windowShadowFg },
|
||||||
{ "calls_maximize_main", callNameFg },
|
{ "calls/calls_maximize_main", callNameFg },
|
||||||
};
|
};
|
||||||
callTitleRestoreIcon: icon {
|
callTitleRestoreIcon: icon {
|
||||||
{ "calls_restore_shadow", windowShadowFg },
|
{ "calls/calls_restore_shadow", windowShadowFg },
|
||||||
{ "calls_restore_main", callNameFg },
|
{ "calls/calls_restore_main", callNameFg },
|
||||||
};
|
};
|
||||||
callTitleRestoreIconOver: icon {
|
callTitleRestoreIconOver: icon {
|
||||||
{ size(34px, 30px), callBgButton },
|
{ size(34px, 30px), callBgButton },
|
||||||
{ size(34px, 30px), callMuteRipple },
|
{ size(34px, 30px), callMuteRipple },
|
||||||
{ "calls_restore_shadow", windowShadowFg },
|
{ "calls/calls_restore_shadow", windowShadowFg },
|
||||||
{ "calls_restore_main", callNameFg },
|
{ "calls/calls_restore_main", callNameFg },
|
||||||
};
|
};
|
||||||
callTitleCloseIcon: icon {
|
callTitleCloseIcon: icon {
|
||||||
{ "calls_close_shadow", windowShadowFg },
|
{ "calls/calls_close_shadow", windowShadowFg },
|
||||||
{ "calls_close_main", callNameFg },
|
{ "calls/calls_close_main", callNameFg },
|
||||||
};
|
};
|
||||||
callTitleCloseIconOver: icon {
|
callTitleCloseIconOver: icon {
|
||||||
{ size(34px, 30px), titleButtonCloseBgOver },
|
{ size(34px, 30px), titleButtonCloseBgOver },
|
||||||
{ "calls_close_shadow", windowShadowFg },
|
{ "calls/calls_close_shadow", windowShadowFg },
|
||||||
{ "calls_close_main", titleButtonCloseFgOver },
|
{ "calls/calls_close_main", titleButtonCloseFgOver },
|
||||||
};
|
};
|
||||||
callTitle: WindowTitle(defaultWindowTitle) {
|
callTitle: WindowTitle(defaultWindowTitle) {
|
||||||
height: 0px;
|
height: 0px;
|
||||||
|
@ -394,7 +394,7 @@ callTitle: WindowTitle(defaultWindowTitle) {
|
||||||
closeIconActive: callTitleCloseIcon;
|
closeIconActive: callTitleCloseIcon;
|
||||||
closeIconActiveOver: callTitleCloseIconOver;
|
closeIconActiveOver: callTitleCloseIconOver;
|
||||||
}
|
}
|
||||||
callTitleShadow: icon {{ "calls_shadow_controls", windowShadowFg }};
|
callTitleShadow: icon {{ "calls/calls_shadow_controls", windowShadowFg }};
|
||||||
|
|
||||||
callErrorToast: Toast(defaultToast) {
|
callErrorToast: Toast(defaultToast) {
|
||||||
minWidth: 240px;
|
minWidth: 240px;
|
||||||
|
@ -402,3 +402,78 @@ callErrorToast: Toast(defaultToast) {
|
||||||
|
|
||||||
groupCallWidth: 380px;
|
groupCallWidth: 380px;
|
||||||
groupCallHeight: 580px;
|
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;
|
||||||
|
|
528
Telegram/SourceFiles/calls/calls_group_members.cpp
Normal 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
|
76
Telegram/SourceFiles/calls/calls_group_members.h
Normal 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
|
|
@ -7,42 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "calls/calls_group_panel.h"
|
#include "calls/calls_group_panel.h"
|
||||||
|
|
||||||
#include "data/data_photo.h"
|
#include "calls/calls_group_members.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 "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/labels.h"
|
|
||||||
#include "ui/widgets/shadow.h"
|
|
||||||
#include "ui/widgets/window.h"
|
#include "ui/widgets/window.h"
|
||||||
#include "ui/effects/ripple_animation.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 "core/application.h"
|
||||||
#include "mainwindow.h"
|
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "main/main_session.h"
|
#include "base/event_filter.h"
|
||||||
#include "apiwrap.h"
|
|
||||||
#include "platform/platform_specific.h"
|
|
||||||
#include "base/platform/base_platform_info.h"
|
|
||||||
#include "window/main_window.h"
|
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "webrtc/webrtc_video_track.h"
|
|
||||||
#include "styles/style_calls.h"
|
#include "styles/style_calls.h"
|
||||||
#include "styles/style_chat.h"
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include "ui/platform/win/ui_window_title_win.h"
|
#include "ui/platform/win/ui_window_title_win.h"
|
||||||
|
@ -246,9 +219,9 @@ GroupPanel::GroupPanel(not_null<GroupCall*> call)
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
, _controls(std::make_unique<Ui::Platform::TitleControls>(
|
, _controls(std::make_unique<Ui::Platform::TitleControls>(
|
||||||
_window.get(),
|
_window.get(),
|
||||||
st::callTitle,
|
st::callTitle))
|
||||||
[=](bool maximized) { toggleFullScreen(maximized); }))
|
|
||||||
#endif // Q_OS_WIN
|
#endif // Q_OS_WIN
|
||||||
|
, _members(widget(), call)
|
||||||
, _settings(widget(), st::callCancel)
|
, _settings(widget(), st::callCancel)
|
||||||
, _hangup(widget(), st::callHangup)
|
, _hangup(widget(), st::callHangup)
|
||||||
, _mute(widget(), st::callMicrophoneMute, &st::callMicrophoneUnmute) {
|
, _mute(widget(), st::callMicrophoneMute, &st::callMicrophoneUnmute) {
|
||||||
|
@ -262,6 +235,9 @@ GroupPanel::GroupPanel(not_null<GroupCall*> call)
|
||||||
GroupPanel::~GroupPanel() = default;
|
GroupPanel::~GroupPanel() = default;
|
||||||
|
|
||||||
void GroupPanel::showAndActivate() {
|
void GroupPanel::showAndActivate() {
|
||||||
|
if (_window->isHidden()) {
|
||||||
|
_window->show();
|
||||||
|
}
|
||||||
_window->raise();
|
_window->raise();
|
||||||
_window->setWindowState(_window->windowState() | Qt::WindowActive);
|
_window->setWindowState(_window->windowState() | Qt::WindowActive);
|
||||||
_window->activateWindow();
|
_window->activateWindow();
|
||||||
|
@ -276,17 +252,13 @@ void GroupPanel::initWindow() {
|
||||||
_window->setTitle(u" "_q);
|
_window->setTitle(u" "_q);
|
||||||
_window->setTitleStyle(st::callTitle);
|
_window->setTitleStyle(st::callTitle);
|
||||||
|
|
||||||
_window->events(
|
base::install_event_filter(_window.get(), [=](not_null<QEvent*> e) {
|
||||||
) | rpl::start_with_next([=](not_null<QEvent*> e) {
|
if (e->type() == QEvent::Close && handleClose()) {
|
||||||
if (e->type() == QEvent::Close) {
|
e->ignore();
|
||||||
handleClose();
|
return base::EventFilterResult::Cancel;
|
||||||
} else if (e->type() == QEvent::KeyPress) {
|
|
||||||
if ((static_cast<QKeyEvent*>(e.get())->key() == Qt::Key_Escape)
|
|
||||||
&& _window->isFullScreen()) {
|
|
||||||
_window->showNormal();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, _window->lifetime());
|
return base::EventFilterResult::Continue;
|
||||||
|
});
|
||||||
|
|
||||||
_window->setBodyTitleArea([=](QPoint widgetPoint) {
|
_window->setBodyTitleArea([=](QPoint widgetPoint) {
|
||||||
using Flag = Ui::WindowTitleHitTestFlag;
|
using Flag = Ui::WindowTitleHitTestFlag;
|
||||||
|
@ -301,31 +273,8 @@ void GroupPanel::initWindow() {
|
||||||
const auto inControls = false;
|
const auto inControls = false;
|
||||||
return inControls
|
return inControls
|
||||||
? Flag::None
|
? 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() {
|
void GroupPanel::initWidget() {
|
||||||
|
@ -382,6 +331,11 @@ void GroupPanel::initWithCall(GroupCall *call) {
|
||||||
) | rpl::start_with_next([=](State state) {
|
) | rpl::start_with_next([=](State state) {
|
||||||
stateChanged(state);
|
stateChanged(state);
|
||||||
}, _callLifetime);
|
}, _callLifetime);
|
||||||
|
|
||||||
|
_members->desiredHeightValue(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
updateControlsGeometry();
|
||||||
|
}, _members->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupPanel::initLayout() {
|
void GroupPanel::initLayout() {
|
||||||
|
@ -412,22 +366,33 @@ void GroupPanel::initGeometry() {
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupPanel::toggleFullScreen(bool fullscreen) {
|
|
||||||
if (fullscreen) {
|
|
||||||
_window->showFullScreen();
|
|
||||||
} else {
|
|
||||||
_window->showNormal();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GroupPanel::updateControlsGeometry() {
|
void GroupPanel::updateControlsGeometry() {
|
||||||
if (widget()->size().isEmpty()) {
|
if (widget()->size().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto top = widget()->height() - 2 * _mute->height();
|
const auto desiredHeight = _members->desiredHeight();
|
||||||
_mute->move((widget()->width() - _mute->width()) / 2, top);
|
const auto membersWidth = widget()->width()
|
||||||
_settings->moveToLeft(_settings->width(), top);
|
- st::groupCallMembersMargin.left()
|
||||||
_hangup->moveToRight(_settings->width(), top);
|
- 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) {
|
void GroupPanel::paint(QRect clip) {
|
||||||
|
@ -435,14 +400,16 @@ void GroupPanel::paint(QRect clip) {
|
||||||
|
|
||||||
auto region = QRegion(clip);
|
auto region = QRegion(clip);
|
||||||
for (const auto rect : region) {
|
for (const auto rect : region) {
|
||||||
p.fillRect(rect, st::callBgOpaque);
|
p.fillRect(rect, st::groupCallBg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroupPanel::handleClose() {
|
bool GroupPanel::handleClose() {
|
||||||
if (_call) {
|
if (_call) {
|
||||||
_call->hangup();
|
_window->hide();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Ui::RpWidget*> GroupPanel::widget() const {
|
not_null<Ui::RpWidget*> GroupPanel::widget() const {
|
||||||
|
|
|
@ -29,6 +29,7 @@ class FadeWrap;
|
||||||
template <typename Widget>
|
template <typename Widget>
|
||||||
class PaddingWrap;
|
class PaddingWrap;
|
||||||
class Window;
|
class Window;
|
||||||
|
class ScrollArea;
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
class TitleControls;
|
class TitleControls;
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
|
@ -44,6 +45,8 @@ namespace Calls {
|
||||||
class Userpic;
|
class Userpic;
|
||||||
class SignalBars;
|
class SignalBars;
|
||||||
|
|
||||||
|
class GroupMembers;
|
||||||
|
|
||||||
class GroupPanel final {
|
class GroupPanel final {
|
||||||
public:
|
public:
|
||||||
GroupPanel(not_null<GroupCall*> call);
|
GroupPanel(not_null<GroupCall*> call);
|
||||||
|
@ -67,14 +70,11 @@ private:
|
||||||
void initLayout();
|
void initLayout();
|
||||||
void initGeometry();
|
void initGeometry();
|
||||||
|
|
||||||
void handleClose();
|
bool handleClose();
|
||||||
|
|
||||||
void updateControlsGeometry();
|
void updateControlsGeometry();
|
||||||
void stateChanged(State state);
|
void stateChanged(State state);
|
||||||
void showControls();
|
void showControls();
|
||||||
void startDurationUpdateTimer(crl::time currentDuration);
|
|
||||||
|
|
||||||
void toggleFullScreen(bool fullscreen);
|
|
||||||
|
|
||||||
GroupCall *_call = nullptr;
|
GroupCall *_call = nullptr;
|
||||||
not_null<ChannelData*> _channel;
|
not_null<ChannelData*> _channel;
|
||||||
|
@ -87,6 +87,8 @@ private:
|
||||||
|
|
||||||
rpl::lifetime _callLifetime;
|
rpl::lifetime _callLifetime;
|
||||||
|
|
||||||
|
object_ptr<GroupMembers> _members;
|
||||||
|
|
||||||
object_ptr<Button> _settings;
|
object_ptr<Button> _settings;
|
||||||
object_ptr<Button> _hangup;
|
object_ptr<Button> _hangup;
|
||||||
object_ptr<Button> _mute;
|
object_ptr<Button> _mute;
|
||||||
|
|
|
@ -35,7 +35,7 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallTracker::content() const {
|
||||||
if (!call || (current && current->channel() == channel)) {
|
if (!call || (current && current->channel() == channel)) {
|
||||||
return { .shown = false };
|
return { .shown = false };
|
||||||
} else if (!call->fullCount() && !call->participantsLoaded()) {
|
} else if (!call->fullCount() && !call->participantsLoaded()) {
|
||||||
call->requestParticipants();
|
call->reload();
|
||||||
}
|
}
|
||||||
return { .count = call->fullCount(), .shown = true };
|
return { .count = call->fullCount(), .shown = true };
|
||||||
});
|
});
|
||||||
|
|
|
@ -517,22 +517,22 @@ historyUnreadBarFont: semiboldFont;
|
||||||
historyForwardChooseMargins: margins(30px, 10px, 30px, 10px);
|
historyForwardChooseMargins: margins(30px, 10px, 30px, 10px);
|
||||||
historyForwardChooseFont: font(16px);
|
historyForwardChooseFont: font(16px);
|
||||||
|
|
||||||
historyCallArrowIn: icon {{ "call_arrow_in", historyCallArrowInFg }};
|
historyCallArrowIn: icon {{ "calls/call_arrow_in", historyCallArrowInFg }};
|
||||||
historyCallArrowInSelected: icon {{ "call_arrow_in", historyCallArrowInFgSelected }};
|
historyCallArrowInSelected: icon {{ "calls/call_arrow_in", historyCallArrowInFgSelected }};
|
||||||
historyCallArrowMissedIn: icon {{ "call_arrow_in", historyCallArrowMissedInFg }};
|
historyCallArrowMissedIn: icon {{ "calls/call_arrow_in", historyCallArrowMissedInFg }};
|
||||||
historyCallArrowMissedInSelected: icon {{ "call_arrow_in", historyCallArrowMissedInFgSelected }};
|
historyCallArrowMissedInSelected: icon {{ "calls/call_arrow_in", historyCallArrowMissedInFgSelected }};
|
||||||
historyCallArrowOut: icon {{ "call_arrow_out", historyCallArrowOutFg }};
|
historyCallArrowOut: icon {{ "calls/call_arrow_out", historyCallArrowOutFg }};
|
||||||
historyCallArrowOutSelected: icon {{ "call_arrow_out", historyCallArrowOutFgSelected }};
|
historyCallArrowOutSelected: icon {{ "calls/call_arrow_out", historyCallArrowOutFgSelected }};
|
||||||
historyCallWidth: 240px;
|
historyCallWidth: 240px;
|
||||||
historyCallHeight: 56px;
|
historyCallHeight: 56px;
|
||||||
historyCallInIcon: icon {{ "call_answer", msgFileInBg }};
|
historyCallInIcon: icon {{ "calls/call_answer", msgFileInBg }};
|
||||||
historyCallInIconSelected: icon {{ "call_answer", msgFileInBgSelected }};
|
historyCallInIconSelected: icon {{ "calls/call_answer", msgFileInBgSelected }};
|
||||||
historyCallOutIcon: icon {{ "call_answer", msgFileOutBg }};
|
historyCallOutIcon: icon {{ "calls/call_answer", msgFileOutBg }};
|
||||||
historyCallOutIconSelected: icon {{ "call_answer", msgFileOutBgSelected }};
|
historyCallOutIconSelected: icon {{ "calls/call_answer", msgFileOutBgSelected }};
|
||||||
historyCallCameraInIcon: icon {{ "call_camera_active", msgFileInBg }};
|
historyCallCameraInIcon: icon {{ "calls/call_camera_active", msgFileInBg }};
|
||||||
historyCallCameraInIconSelected: icon {{ "call_camera_active", msgFileInBgSelected }};
|
historyCallCameraInIconSelected: icon {{ "calls/call_camera_active", msgFileInBgSelected }};
|
||||||
historyCallCameraOutIcon: icon {{ "call_camera_active", msgFileOutBg }};
|
historyCallCameraOutIcon: icon {{ "calls/call_camera_active", msgFileOutBg }};
|
||||||
historyCallCameraOutIconSelected: icon {{ "call_camera_active", msgFileOutBgSelected }};
|
historyCallCameraOutIconSelected: icon {{ "calls/call_camera_active", msgFileOutBgSelected }};
|
||||||
historyCallIconPosition: point(12px, 10px);
|
historyCallIconPosition: point(12px, 10px);
|
||||||
historyCallLeft: 16px;
|
historyCallLeft: 16px;
|
||||||
historyCallTop: 9px;
|
historyCallTop: 9px;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit f06346fbf03900c278e1d59717e1387bffc03f39
|
Subproject commit e73bae12e26811f70adff5adfafbdb2548e02cd0
|