diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index a483dabc4..c64e375c1 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -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 diff --git a/Telegram/Resources/icons/call_answer.png b/Telegram/Resources/icons/calls/call_answer.png similarity index 100% rename from Telegram/Resources/icons/call_answer.png rename to Telegram/Resources/icons/calls/call_answer.png diff --git a/Telegram/Resources/icons/call_answer@2x.png b/Telegram/Resources/icons/calls/call_answer@2x.png similarity index 100% rename from Telegram/Resources/icons/call_answer@2x.png rename to Telegram/Resources/icons/calls/call_answer@2x.png diff --git a/Telegram/Resources/icons/call_answer@3x.png b/Telegram/Resources/icons/calls/call_answer@3x.png similarity index 100% rename from Telegram/Resources/icons/call_answer@3x.png rename to Telegram/Resources/icons/calls/call_answer@3x.png diff --git a/Telegram/Resources/icons/call_arrow_in.png b/Telegram/Resources/icons/calls/call_arrow_in.png similarity index 100% rename from Telegram/Resources/icons/call_arrow_in.png rename to Telegram/Resources/icons/calls/call_arrow_in.png diff --git a/Telegram/Resources/icons/call_arrow_in@2x.png b/Telegram/Resources/icons/calls/call_arrow_in@2x.png similarity index 100% rename from Telegram/Resources/icons/call_arrow_in@2x.png rename to Telegram/Resources/icons/calls/call_arrow_in@2x.png diff --git a/Telegram/Resources/icons/call_arrow_in@3x.png b/Telegram/Resources/icons/calls/call_arrow_in@3x.png similarity index 100% rename from Telegram/Resources/icons/call_arrow_in@3x.png rename to Telegram/Resources/icons/calls/call_arrow_in@3x.png diff --git a/Telegram/Resources/icons/call_arrow_out.png b/Telegram/Resources/icons/calls/call_arrow_out.png similarity index 100% rename from Telegram/Resources/icons/call_arrow_out.png rename to Telegram/Resources/icons/calls/call_arrow_out.png diff --git a/Telegram/Resources/icons/call_arrow_out@2x.png b/Telegram/Resources/icons/calls/call_arrow_out@2x.png similarity index 100% rename from Telegram/Resources/icons/call_arrow_out@2x.png rename to Telegram/Resources/icons/calls/call_arrow_out@2x.png diff --git a/Telegram/Resources/icons/call_arrow_out@3x.png b/Telegram/Resources/icons/calls/call_arrow_out@3x.png similarity index 100% rename from Telegram/Resources/icons/call_arrow_out@3x.png rename to Telegram/Resources/icons/calls/call_arrow_out@3x.png diff --git a/Telegram/Resources/icons/call_camera_active.png b/Telegram/Resources/icons/calls/call_camera_active.png similarity index 100% rename from Telegram/Resources/icons/call_camera_active.png rename to Telegram/Resources/icons/calls/call_camera_active.png diff --git a/Telegram/Resources/icons/call_camera_active@2x.png b/Telegram/Resources/icons/calls/call_camera_active@2x.png similarity index 100% rename from Telegram/Resources/icons/call_camera_active@2x.png rename to Telegram/Resources/icons/calls/call_camera_active@2x.png diff --git a/Telegram/Resources/icons/call_camera_active@3x.png b/Telegram/Resources/icons/calls/call_camera_active@3x.png similarity index 100% rename from Telegram/Resources/icons/call_camera_active@3x.png rename to Telegram/Resources/icons/calls/call_camera_active@3x.png diff --git a/Telegram/Resources/icons/call_camera_muted.png b/Telegram/Resources/icons/calls/call_camera_muted.png similarity index 100% rename from Telegram/Resources/icons/call_camera_muted.png rename to Telegram/Resources/icons/calls/call_camera_muted.png diff --git a/Telegram/Resources/icons/call_camera_muted@2x.png b/Telegram/Resources/icons/calls/call_camera_muted@2x.png similarity index 100% rename from Telegram/Resources/icons/call_camera_muted@2x.png rename to Telegram/Resources/icons/calls/call_camera_muted@2x.png diff --git a/Telegram/Resources/icons/call_camera_muted@3x.png b/Telegram/Resources/icons/calls/call_camera_muted@3x.png similarity index 100% rename from Telegram/Resources/icons/call_camera_muted@3x.png rename to Telegram/Resources/icons/calls/call_camera_muted@3x.png diff --git a/Telegram/Resources/icons/call_cancel.png b/Telegram/Resources/icons/calls/call_cancel.png similarity index 100% rename from Telegram/Resources/icons/call_cancel.png rename to Telegram/Resources/icons/calls/call_cancel.png diff --git a/Telegram/Resources/icons/call_cancel@2x.png b/Telegram/Resources/icons/calls/call_cancel@2x.png similarity index 100% rename from Telegram/Resources/icons/call_cancel@2x.png rename to Telegram/Resources/icons/calls/call_cancel@2x.png diff --git a/Telegram/Resources/icons/call_cancel@3x.png b/Telegram/Resources/icons/calls/call_cancel@3x.png similarity index 100% rename from Telegram/Resources/icons/call_cancel@3x.png rename to Telegram/Resources/icons/calls/call_cancel@3x.png diff --git a/Telegram/Resources/icons/call_discard.png b/Telegram/Resources/icons/calls/call_discard.png similarity index 100% rename from Telegram/Resources/icons/call_discard.png rename to Telegram/Resources/icons/calls/call_discard.png diff --git a/Telegram/Resources/icons/call_discard@2x.png b/Telegram/Resources/icons/calls/call_discard@2x.png similarity index 100% rename from Telegram/Resources/icons/call_discard@2x.png rename to Telegram/Resources/icons/calls/call_discard@2x.png diff --git a/Telegram/Resources/icons/call_discard@3x.png b/Telegram/Resources/icons/calls/call_discard@3x.png similarity index 100% rename from Telegram/Resources/icons/call_discard@3x.png rename to Telegram/Resources/icons/calls/call_discard@3x.png diff --git a/Telegram/Resources/icons/call_rating.png b/Telegram/Resources/icons/calls/call_rating.png similarity index 100% rename from Telegram/Resources/icons/call_rating.png rename to Telegram/Resources/icons/calls/call_rating.png diff --git a/Telegram/Resources/icons/call_rating@2x.png b/Telegram/Resources/icons/calls/call_rating@2x.png similarity index 100% rename from Telegram/Resources/icons/call_rating@2x.png rename to Telegram/Resources/icons/calls/call_rating@2x.png diff --git a/Telegram/Resources/icons/call_rating@3x.png b/Telegram/Resources/icons/calls/call_rating@3x.png similarity index 100% rename from Telegram/Resources/icons/call_rating@3x.png rename to Telegram/Resources/icons/calls/call_rating@3x.png diff --git a/Telegram/Resources/icons/call_rating_filled.png b/Telegram/Resources/icons/calls/call_rating_filled.png similarity index 100% rename from Telegram/Resources/icons/call_rating_filled.png rename to Telegram/Resources/icons/calls/call_rating_filled.png diff --git a/Telegram/Resources/icons/call_rating_filled@2x.png b/Telegram/Resources/icons/calls/call_rating_filled@2x.png similarity index 100% rename from Telegram/Resources/icons/call_rating_filled@2x.png rename to Telegram/Resources/icons/calls/call_rating_filled@2x.png diff --git a/Telegram/Resources/icons/call_rating_filled@3x.png b/Telegram/Resources/icons/calls/call_rating_filled@3x.png similarity index 100% rename from Telegram/Resources/icons/call_rating_filled@3x.png rename to Telegram/Resources/icons/calls/call_rating_filled@3x.png diff --git a/Telegram/Resources/icons/call_record_active.png b/Telegram/Resources/icons/calls/call_record_active.png similarity index 100% rename from Telegram/Resources/icons/call_record_active.png rename to Telegram/Resources/icons/calls/call_record_active.png diff --git a/Telegram/Resources/icons/call_record_active@2x.png b/Telegram/Resources/icons/calls/call_record_active@2x.png similarity index 100% rename from Telegram/Resources/icons/call_record_active@2x.png rename to Telegram/Resources/icons/calls/call_record_active@2x.png diff --git a/Telegram/Resources/icons/call_record_active@3x.png b/Telegram/Resources/icons/calls/call_record_active@3x.png similarity index 100% rename from Telegram/Resources/icons/call_record_active@3x.png rename to Telegram/Resources/icons/calls/call_record_active@3x.png diff --git a/Telegram/Resources/icons/call_record_muted.png b/Telegram/Resources/icons/calls/call_record_muted.png similarity index 100% rename from Telegram/Resources/icons/call_record_muted.png rename to Telegram/Resources/icons/calls/call_record_muted.png diff --git a/Telegram/Resources/icons/call_record_muted@2x.png b/Telegram/Resources/icons/calls/call_record_muted@2x.png similarity index 100% rename from Telegram/Resources/icons/call_record_muted@2x.png rename to Telegram/Resources/icons/calls/call_record_muted@2x.png diff --git a/Telegram/Resources/icons/call_record_muted@3x.png b/Telegram/Resources/icons/calls/call_record_muted@3x.png similarity index 100% rename from Telegram/Resources/icons/call_record_muted@3x.png rename to Telegram/Resources/icons/calls/call_record_muted@3x.png diff --git a/Telegram/Resources/icons/call_shadow_left.png b/Telegram/Resources/icons/calls/call_shadow_left.png similarity index 100% rename from Telegram/Resources/icons/call_shadow_left.png rename to Telegram/Resources/icons/calls/call_shadow_left.png diff --git a/Telegram/Resources/icons/call_shadow_left@2x.png b/Telegram/Resources/icons/calls/call_shadow_left@2x.png similarity index 100% rename from Telegram/Resources/icons/call_shadow_left@2x.png rename to Telegram/Resources/icons/calls/call_shadow_left@2x.png diff --git a/Telegram/Resources/icons/call_shadow_left@3x.png b/Telegram/Resources/icons/calls/call_shadow_left@3x.png similarity index 100% rename from Telegram/Resources/icons/call_shadow_left@3x.png rename to Telegram/Resources/icons/calls/call_shadow_left@3x.png diff --git a/Telegram/Resources/icons/call_shadow_top.png b/Telegram/Resources/icons/calls/call_shadow_top.png similarity index 100% rename from Telegram/Resources/icons/call_shadow_top.png rename to Telegram/Resources/icons/calls/call_shadow_top.png diff --git a/Telegram/Resources/icons/call_shadow_top@2x.png b/Telegram/Resources/icons/calls/call_shadow_top@2x.png similarity index 100% rename from Telegram/Resources/icons/call_shadow_top@2x.png rename to Telegram/Resources/icons/calls/call_shadow_top@2x.png diff --git a/Telegram/Resources/icons/call_shadow_top@3x.png b/Telegram/Resources/icons/calls/call_shadow_top@3x.png similarity index 100% rename from Telegram/Resources/icons/call_shadow_top@3x.png rename to Telegram/Resources/icons/calls/call_shadow_top@3x.png diff --git a/Telegram/Resources/icons/call_shadow_top_left.png b/Telegram/Resources/icons/calls/call_shadow_top_left.png similarity index 100% rename from Telegram/Resources/icons/call_shadow_top_left.png rename to Telegram/Resources/icons/calls/call_shadow_top_left.png diff --git a/Telegram/Resources/icons/call_shadow_top_left@2x.png b/Telegram/Resources/icons/calls/call_shadow_top_left@2x.png similarity index 100% rename from Telegram/Resources/icons/call_shadow_top_left@2x.png rename to Telegram/Resources/icons/calls/call_shadow_top_left@2x.png diff --git a/Telegram/Resources/icons/call_shadow_top_left@3x.png b/Telegram/Resources/icons/calls/call_shadow_top_left@3x.png similarity index 100% rename from Telegram/Resources/icons/call_shadow_top_left@3x.png rename to Telegram/Resources/icons/calls/call_shadow_top_left@3x.png diff --git a/Telegram/Resources/icons/calls_close_main.png b/Telegram/Resources/icons/calls/calls_close_main.png similarity index 100% rename from Telegram/Resources/icons/calls_close_main.png rename to Telegram/Resources/icons/calls/calls_close_main.png diff --git a/Telegram/Resources/icons/calls_close_main@2x.png b/Telegram/Resources/icons/calls/calls_close_main@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_close_main@2x.png rename to Telegram/Resources/icons/calls/calls_close_main@2x.png diff --git a/Telegram/Resources/icons/calls_close_main@3x.png b/Telegram/Resources/icons/calls/calls_close_main@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_close_main@3x.png rename to Telegram/Resources/icons/calls/calls_close_main@3x.png diff --git a/Telegram/Resources/icons/calls_close_shadow.png b/Telegram/Resources/icons/calls/calls_close_shadow.png similarity index 100% rename from Telegram/Resources/icons/calls_close_shadow.png rename to Telegram/Resources/icons/calls/calls_close_shadow.png diff --git a/Telegram/Resources/icons/calls_close_shadow@2x.png b/Telegram/Resources/icons/calls/calls_close_shadow@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_close_shadow@2x.png rename to Telegram/Resources/icons/calls/calls_close_shadow@2x.png diff --git a/Telegram/Resources/icons/calls_close_shadow@3x.png b/Telegram/Resources/icons/calls/calls_close_shadow@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_close_shadow@3x.png rename to Telegram/Resources/icons/calls/calls_close_shadow@3x.png diff --git a/Telegram/Resources/icons/calls_maximize_main.png b/Telegram/Resources/icons/calls/calls_maximize_main.png similarity index 100% rename from Telegram/Resources/icons/calls_maximize_main.png rename to Telegram/Resources/icons/calls/calls_maximize_main.png diff --git a/Telegram/Resources/icons/calls_maximize_main@2x.png b/Telegram/Resources/icons/calls/calls_maximize_main@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_maximize_main@2x.png rename to Telegram/Resources/icons/calls/calls_maximize_main@2x.png diff --git a/Telegram/Resources/icons/calls_maximize_main@3x.png b/Telegram/Resources/icons/calls/calls_maximize_main@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_maximize_main@3x.png rename to Telegram/Resources/icons/calls/calls_maximize_main@3x.png diff --git a/Telegram/Resources/icons/calls_maximize_shadow.png b/Telegram/Resources/icons/calls/calls_maximize_shadow.png similarity index 100% rename from Telegram/Resources/icons/calls_maximize_shadow.png rename to Telegram/Resources/icons/calls/calls_maximize_shadow.png diff --git a/Telegram/Resources/icons/calls_maximize_shadow@2x.png b/Telegram/Resources/icons/calls/calls_maximize_shadow@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_maximize_shadow@2x.png rename to Telegram/Resources/icons/calls/calls_maximize_shadow@2x.png diff --git a/Telegram/Resources/icons/calls_maximize_shadow@3x.png b/Telegram/Resources/icons/calls/calls_maximize_shadow@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_maximize_shadow@3x.png rename to Telegram/Resources/icons/calls/calls_maximize_shadow@3x.png diff --git a/Telegram/Resources/icons/calls_minimize_main.png b/Telegram/Resources/icons/calls/calls_minimize_main.png similarity index 100% rename from Telegram/Resources/icons/calls_minimize_main.png rename to Telegram/Resources/icons/calls/calls_minimize_main.png diff --git a/Telegram/Resources/icons/calls_minimize_main@2x.png b/Telegram/Resources/icons/calls/calls_minimize_main@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_minimize_main@2x.png rename to Telegram/Resources/icons/calls/calls_minimize_main@2x.png diff --git a/Telegram/Resources/icons/calls_minimize_main@3x.png b/Telegram/Resources/icons/calls/calls_minimize_main@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_minimize_main@3x.png rename to Telegram/Resources/icons/calls/calls_minimize_main@3x.png diff --git a/Telegram/Resources/icons/calls_minimize_shadow.png b/Telegram/Resources/icons/calls/calls_minimize_shadow.png similarity index 100% rename from Telegram/Resources/icons/calls_minimize_shadow.png rename to Telegram/Resources/icons/calls/calls_minimize_shadow.png diff --git a/Telegram/Resources/icons/calls_minimize_shadow@2x.png b/Telegram/Resources/icons/calls/calls_minimize_shadow@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_minimize_shadow@2x.png rename to Telegram/Resources/icons/calls/calls_minimize_shadow@2x.png diff --git a/Telegram/Resources/icons/calls_minimize_shadow@3x.png b/Telegram/Resources/icons/calls/calls_minimize_shadow@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_minimize_shadow@3x.png rename to Telegram/Resources/icons/calls/calls_minimize_shadow@3x.png diff --git a/Telegram/Resources/icons/calls_mute_tooltip.png b/Telegram/Resources/icons/calls/calls_mute_tooltip.png similarity index 100% rename from Telegram/Resources/icons/calls_mute_tooltip.png rename to Telegram/Resources/icons/calls/calls_mute_tooltip.png diff --git a/Telegram/Resources/icons/calls_mute_tooltip@2x.png b/Telegram/Resources/icons/calls/calls_mute_tooltip@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_mute_tooltip@2x.png rename to Telegram/Resources/icons/calls/calls_mute_tooltip@2x.png diff --git a/Telegram/Resources/icons/calls_mute_tooltip@3x.png b/Telegram/Resources/icons/calls/calls_mute_tooltip@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_mute_tooltip@3x.png rename to Telegram/Resources/icons/calls/calls_mute_tooltip@3x.png diff --git a/Telegram/Resources/icons/calls_mute_userpic.png b/Telegram/Resources/icons/calls/calls_mute_userpic.png similarity index 100% rename from Telegram/Resources/icons/calls_mute_userpic.png rename to Telegram/Resources/icons/calls/calls_mute_userpic.png diff --git a/Telegram/Resources/icons/calls_mute_userpic@2x.png b/Telegram/Resources/icons/calls/calls_mute_userpic@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_mute_userpic@2x.png rename to Telegram/Resources/icons/calls/calls_mute_userpic@2x.png diff --git a/Telegram/Resources/icons/calls_mute_userpic@3x.png b/Telegram/Resources/icons/calls/calls_mute_userpic@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_mute_userpic@3x.png rename to Telegram/Resources/icons/calls/calls_mute_userpic@3x.png diff --git a/Telegram/Resources/icons/calls_restore_main.png b/Telegram/Resources/icons/calls/calls_restore_main.png similarity index 100% rename from Telegram/Resources/icons/calls_restore_main.png rename to Telegram/Resources/icons/calls/calls_restore_main.png diff --git a/Telegram/Resources/icons/calls_restore_main@2x.png b/Telegram/Resources/icons/calls/calls_restore_main@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_restore_main@2x.png rename to Telegram/Resources/icons/calls/calls_restore_main@2x.png diff --git a/Telegram/Resources/icons/calls_restore_main@3x.png b/Telegram/Resources/icons/calls/calls_restore_main@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_restore_main@3x.png rename to Telegram/Resources/icons/calls/calls_restore_main@3x.png diff --git a/Telegram/Resources/icons/calls_restore_shadow.png b/Telegram/Resources/icons/calls/calls_restore_shadow.png similarity index 100% rename from Telegram/Resources/icons/calls_restore_shadow.png rename to Telegram/Resources/icons/calls/calls_restore_shadow.png diff --git a/Telegram/Resources/icons/calls_restore_shadow@2x.png b/Telegram/Resources/icons/calls/calls_restore_shadow@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_restore_shadow@2x.png rename to Telegram/Resources/icons/calls/calls_restore_shadow@2x.png diff --git a/Telegram/Resources/icons/calls_restore_shadow@3x.png b/Telegram/Resources/icons/calls/calls_restore_shadow@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_restore_shadow@3x.png rename to Telegram/Resources/icons/calls/calls_restore_shadow@3x.png diff --git a/Telegram/Resources/icons/calls_shadow_controls.png b/Telegram/Resources/icons/calls/calls_shadow_controls.png similarity index 100% rename from Telegram/Resources/icons/calls_shadow_controls.png rename to Telegram/Resources/icons/calls/calls_shadow_controls.png diff --git a/Telegram/Resources/icons/calls_shadow_controls@2x.png b/Telegram/Resources/icons/calls/calls_shadow_controls@2x.png similarity index 100% rename from Telegram/Resources/icons/calls_shadow_controls@2x.png rename to Telegram/Resources/icons/calls/calls_shadow_controls@2x.png diff --git a/Telegram/Resources/icons/calls_shadow_controls@3x.png b/Telegram/Resources/icons/calls/calls_shadow_controls@3x.png similarity index 100% rename from Telegram/Resources/icons/calls_shadow_controls@3x.png rename to Telegram/Resources/icons/calls/calls_shadow_controls@3x.png diff --git a/Telegram/Resources/icons/calls/group_calls_muted.png b/Telegram/Resources/icons/calls/group_calls_muted.png new file mode 100644 index 000000000..1c63be9cd Binary files /dev/null and b/Telegram/Resources/icons/calls/group_calls_muted.png differ diff --git a/Telegram/Resources/icons/calls/group_calls_muted@2x.png b/Telegram/Resources/icons/calls/group_calls_muted@2x.png new file mode 100644 index 000000000..231ce293f Binary files /dev/null and b/Telegram/Resources/icons/calls/group_calls_muted@2x.png differ diff --git a/Telegram/Resources/icons/calls/group_calls_muted@3x.png b/Telegram/Resources/icons/calls/group_calls_muted@3x.png new file mode 100644 index 000000000..7eaf73940 Binary files /dev/null and b/Telegram/Resources/icons/calls/group_calls_muted@3x.png differ diff --git a/Telegram/Resources/icons/calls/group_calls_unmuted.png b/Telegram/Resources/icons/calls/group_calls_unmuted.png new file mode 100644 index 000000000..213b54d8a Binary files /dev/null and b/Telegram/Resources/icons/calls/group_calls_unmuted.png differ diff --git a/Telegram/Resources/icons/calls/group_calls_unmuted@2x.png b/Telegram/Resources/icons/calls/group_calls_unmuted@2x.png new file mode 100644 index 000000000..a3f4b226a Binary files /dev/null and b/Telegram/Resources/icons/calls/group_calls_unmuted@2x.png differ diff --git a/Telegram/Resources/icons/calls/group_calls_unmuted@3x.png b/Telegram/Resources/icons/calls/group_calls_unmuted@3x.png new file mode 100644 index 000000000..e351c3996 Binary files /dev/null and b/Telegram/Resources/icons/calls/group_calls_unmuted@3x.png differ diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style index 95e70e64b..e52f6e7a8 100644 --- a/Telegram/SourceFiles/boxes/boxes.style +++ b/Telegram/SourceFiles/boxes/boxes.style @@ -219,7 +219,6 @@ contactsPhotoCheckIcon: defaultPeerListCheckIcon; contactsPhotoCheck: defaultPeerListCheck; contactsPhotoCheckbox: defaultPeerListCheckbox; contactsPhotoDisabledCheckFg: menuIconFg; -contactsNameCheckedFg: windowActiveTextFg; contactsRipple: defaultRippleAnimation; contactsMarginTop: 4px; diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index 5a08ed6e7..2ed83d917 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -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()) { diff --git a/Telegram/SourceFiles/boxes/peers/edit_participants_box.h b/Telegram/SourceFiles/boxes/peers/edit_participants_box.h index 65d8994fa..0c3264b35 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_participants_box.h +++ b/Telegram/SourceFiles/boxes/peers/edit_participants_box.h @@ -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; diff --git a/Telegram/SourceFiles/calls/calls.style b/Telegram/SourceFiles/calls/calls.style index 91441586b..ad0a7aeea 100644 --- a/Telegram/SourceFiles/calls/calls.style +++ b/Telegram/SourceFiles/calls/calls.style @@ -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; diff --git a/Telegram/SourceFiles/calls/calls_group_members.cpp b/Telegram/SourceFiles/calls/calls_group_members.cpp new file mode 100644 index 000000000..d3826d5c5 --- /dev/null +++ b/Telegram/SourceFiles/calls/calls_group_members.cpp @@ -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 call); + + Main::Session &session() const override; + void prepare() override; + void rowClicked(not_null row) override; + void rowActionClicked(not_null row) override; + base::unique_qptr rowContextMenu( + QWidget *parent, + not_null row) override; + void loadMoreRows() override; + +private: + [[nodiscard]] std::unique_ptr createRow( + not_null user) const; + + void prepareRows(); + + void setupListChangeViewers(); + bool appendRow(not_null user); + bool prependRow(not_null user); + bool removeRow(not_null user); + + const base::weak_ptr _call; + const not_null _channel; + + Ui::BoxPointer _addBox; + rpl::lifetime _lifetime; + +}; + +class Row final : public PeerListRow { +public: + Row(not_null channel, not_null user); + + enum class State { + Active, + Inactive, + Muted, + }; + + void addActionRipple(QPoint point, Fn 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 channel, + not_null user); + [[nodiscard]] static not_null ComputeIconStyle( + State state); + + State _state = State::Inactive; + not_null _st; + + std::unique_ptr _actionRipple; + +}; + +Row::Row(not_null channel, not_null 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 channel, + not_null 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 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 updateCallback) { + if (!_actionRipple) { + auto mask = Ui::RippleAnimation::ellipseMask( + QSize(_st->rippleAreaSize, _st->rippleAreaSize)); + _actionRipple = std::make_unique( + _st->ripple, + std::move(mask), + std::move(updateCallback)); + } + _actionRipple->add(point - _st->rippleAreaPosition); +} + +void Row::stopLastActionRipple() { + if (_actionRipple) { + _actionRipple->lastStop(); + } +} + +MembersController::MembersController(not_null 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 row) { + Expects(row->peer()->isUser()); + + const auto user = row->peer()->asUser(); +} + +void MembersController::rowActionClicked( + not_null row) { + Expects(row->peer()->isUser()); + + const auto user = row->peer()->asUser(); +} + +base::unique_qptr MembersController::rowContextMenu( + QWidget *parent, + not_null row) { + Expects(row->peer()->isUser()); + + const auto user = row->peer()->asUser(); + auto result = base::make_unique_q(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 user) { + if (delegate()->peerListFindRow(user->id)) { + return false; + } + delegate()->peerListAppendRow(createRow(user)); + return true; +} + +bool MembersController::prependRow(not_null user) { + if (auto row = delegate()->peerListFindRow(user->id)) { + return false; + } + delegate()->peerListPrependRow(createRow(user)); + return true; +} + +bool MembersController::removeRow(not_null user) { + if (auto row = delegate()->peerListFindRow(user->id)) { + delegate()->peerListRemoveRow(row); + return true; + } + return false; +} + +std::unique_ptr MembersController::createRow( + not_null user) const { + return std::make_unique(_channel, user); +} + +} // namespace + +GroupMembers::GroupMembers( + QWidget *parent, + not_null call) +: RpWidget(parent) +, _call(call) +, _scroll(this, st::defaultSolidScroll) +, _listController(std::make_unique(call)) { + setupHeader(call); + setupList(); + setContent(_list); + _listController->setDelegate(static_cast(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 call) { + _header = object_ptr( + this, + st::groupCallMembersHeader); + auto parent = _header.data(); + + _titleWrap = Ui::CreateChild(parent); + _title = setupTitle(call); + _addMember = Ui::CreateChild( + parent, + st::groupCallAddMember); + setupButtons(); + + widthValue( + ) | rpl::start_with_next([this](int width) { + _header->resizeToWidth(width); + }, _header->lifetime()); +} + +object_ptr GroupMembers::setupTitle( + not_null 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( + _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( + 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 title) { +} + +void GroupMembers::peerListSetAdditionalTitle(rpl::producer title) { +} + +bool GroupMembers::peerListIsRowChecked(not_null row) { + return false; +} + +void GroupMembers::peerListScrollToTop() { +} + +int GroupMembers::peerListSelectedRowsCount() { + return 0; +} + +std::vector> GroupMembers::peerListCollectSelectedRows() { + return {}; +} + +void GroupMembers::peerListAddSelectedPeerInBunch(not_null peer) { + Unexpected("Item selection in Info::Profile::Members."); +} + +void GroupMembers::peerListAddSelectedRowInBunch(not_null row) { + Unexpected("Item selection in Info::Profile::Members."); +} + +void GroupMembers::peerListFinishSelectedRowsBunch() { +} + +void GroupMembers::peerListSetDescription( + object_ptr description) { + description.destroy(); +} + +} // namespace Calls diff --git a/Telegram/SourceFiles/calls/calls_group_members.h b/Telegram/SourceFiles/calls/calls_group_members.h new file mode 100644 index 000000000..ff1c46385 --- /dev/null +++ b/Telegram/SourceFiles/calls/calls_group_members.h @@ -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 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 title) override; + void peerListSetAdditionalTitle(rpl::producer title) override; + bool peerListIsRowChecked(not_null row) override; + int peerListSelectedRowsCount() override; + void peerListScrollToTop() override; + std::vector> peerListCollectSelectedRows() override; + void peerListAddSelectedPeerInBunch( + not_null peer) override; + void peerListAddSelectedRowInBunch( + not_null row) override; + void peerListFinishSelectedRowsBunch() override; + void peerListSetDescription( + object_ptr description) override; + + void setupHeader(not_null call); + object_ptr setupTitle(not_null call); + void setupList(); + + void setupButtons(); + + void addMember(); + void showMembersWithSearch(bool withSearch); + void updateHeaderControlsGeometry(int newWidth); + + base::weak_ptr _call; + object_ptr _scroll; + std::unique_ptr _listController; + object_ptr _header = { nullptr }; + ListWidget *_list = { nullptr }; + + Ui::RpWidget *_titleWrap = nullptr; + Ui::FlatLabel *_title = nullptr; + Ui::IconButton *_addMember = nullptr; + +}; + +} // namespace Calls diff --git a/Telegram/SourceFiles/calls/calls_group_panel.cpp b/Telegram/SourceFiles/calls/calls_group_panel.cpp index 4309519e4..167173a63 100644 --- a/Telegram/SourceFiles/calls/calls_group_panel.cpp +++ b/Telegram/SourceFiles/calls/calls_group_panel.cpp @@ -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 call) #ifdef Q_OS_WIN , _controls(std::make_unique( _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 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 e) { - if (e->type() == QEvent::Close) { - handleClose(); - } else if (e->type() == QEvent::KeyPress) { - if ((static_cast(e.get())->key() == Qt::Key_Escape) - && _window->isFullScreen()) { - _window->showNormal(); - } + base::install_event_filter(_window.get(), [=](not_null 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 GroupPanel::widget() const { diff --git a/Telegram/SourceFiles/calls/calls_group_panel.h b/Telegram/SourceFiles/calls/calls_group_panel.h index cec1fc107..54d98a343 100644 --- a/Telegram/SourceFiles/calls/calls_group_panel.h +++ b/Telegram/SourceFiles/calls/calls_group_panel.h @@ -29,6 +29,7 @@ class FadeWrap; template 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 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 _channel; @@ -87,6 +87,8 @@ private: rpl::lifetime _callLifetime; + object_ptr _members; + object_ptr