mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-19 15:47:11 +02:00
Add member menu on click in group call members list.
This commit is contained in:
parent
834516d4a7
commit
53052c6140
7 changed files with 207 additions and 28 deletions
|
@ -1846,6 +1846,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_group_call_members#other" = "{count} members";
|
||||
"lng_group_call_no_anonymous" = "Anonymous admins can't join voice chats :(";
|
||||
"lng_group_call_context_mute" = "Mute";
|
||||
"lng_group_call_context_unmute" = "Unmute";
|
||||
|
||||
"lng_no_mic_permission" = "Telegram needs access to your microphone so that you can make calls and record voice messages.";
|
||||
|
||||
|
|
|
@ -409,6 +409,36 @@ groupCallHeight: 580px;
|
|||
groupCallRipple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: groupCallMembersBgRipple;
|
||||
}
|
||||
|
||||
groupCallMenu: Menu(defaultMenu) {
|
||||
itemBg: groupCallMembersBgOver;
|
||||
itemBgOver: groupCallMembersBgRipple;
|
||||
itemFg: groupCallMembersFg;
|
||||
itemFgOver: groupCallMembersFg;
|
||||
itemFgDisabled: groupCallMemberNotJoinedStatus;
|
||||
itemFgShortcut: groupCallMemberNotJoinedStatus;
|
||||
itemFgShortcutOver: groupCallMemberNotJoinedStatus;
|
||||
itemFgShortcutDisabled: groupCallMemberNotJoinedStatus;
|
||||
|
||||
separatorFg: groupCallMemberNotJoinedStatus;
|
||||
|
||||
arrow: icon {{ "dropdown_submenu_arrow", groupCallMemberNotJoinedStatus }};
|
||||
|
||||
ripple: groupCallRipple;
|
||||
}
|
||||
groupCallMenuShadow: Shadow(defaultEmptyShadow) {
|
||||
fallback: groupCallMembersBgOver;
|
||||
}
|
||||
groupCallPanelAnimation: PanelAnimation(defaultPanelAnimation) {
|
||||
fadeBg: groupCallMembersBgOver;
|
||||
shadow: groupCallMenuShadow;
|
||||
}
|
||||
groupCallPopupMenu: PopupMenu(defaultPopupMenu) {
|
||||
shadow: groupCallMenuShadow;
|
||||
menu: groupCallMenu;
|
||||
animation: groupCallPanelAnimation;
|
||||
}
|
||||
|
||||
groupCallMembersListItem: PeerListItem(defaultPeerListItem) {
|
||||
button: OutlineButton(defaultPeerListButton) {
|
||||
textBg: groupCallMembersBg;
|
||||
|
@ -470,6 +500,7 @@ groupCallMultiSelect: MultiSelect(defaultMultiSelect) {
|
|||
placeholderFg: groupCallMemberNotJoinedStatus;
|
||||
placeholderFgActive: groupCallMemberNotJoinedStatus;
|
||||
placeholderFgError: groupCallMemberNotJoinedStatus;
|
||||
menu: groupCallPopupMenu;
|
||||
}
|
||||
fieldIcon: icon {{ "box_search", groupCallMemberNotJoinedStatus, point(10px, 9px) }};
|
||||
fieldCancel: CrossButton(defaultMultiSelectSearchCancel) {
|
||||
|
@ -559,9 +590,7 @@ groupCallBox: Box(defaultBox) {
|
|||
textBg: groupCallMembersBg;
|
||||
textBgOver: groupCallMembersBgOver;
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: groupCallMembersBgRipple;
|
||||
}
|
||||
ripple: groupCallRipple;
|
||||
}
|
||||
margin: margins(0px, 56px, 0px, 10px);
|
||||
bg: groupCallMembersBg;
|
||||
|
@ -612,9 +641,7 @@ groupCallSettingsButton: SettingsButton {
|
|||
height: 20px;
|
||||
padding: margins(22px, 10px, 22px, 8px);
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: groupCallMembersBgRipple;
|
||||
}
|
||||
ripple: groupCallRipple;
|
||||
}
|
||||
groupCallSettingsAttentionButton: SettingsButton(groupCallSettingsButton) {
|
||||
textFg: attentionButtonFg;
|
||||
|
|
|
@ -18,12 +18,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "core/application.h" // Core::App().domain, Core::App().activeWindow.
|
||||
#include "main/main_domain.h" // Core::App().domain().activate.
|
||||
#include "main/main_session.h"
|
||||
#include "base/timer.h"
|
||||
#include "boxes/peers/edit_participants_box.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "facades.h" // Ui::showPeerHistory.
|
||||
#include "mainwindow.h" // App::wnd()->activate.
|
||||
#include "window/window_controller.h" // Controller::sessionController.
|
||||
#include "window/window_session_controller.h"
|
||||
#include "styles/style_calls.h"
|
||||
|
||||
namespace Calls {
|
||||
|
@ -107,7 +109,9 @@ class MembersController final
|
|||
: public PeerListController
|
||||
, public base::has_weak_ptr {
|
||||
public:
|
||||
explicit MembersController(not_null<GroupCall*> call);
|
||||
MembersController(
|
||||
not_null<GroupCall*> call,
|
||||
not_null<QWidget*> menuParent);
|
||||
|
||||
using MuteRequest = GroupMembers::MuteRequest;
|
||||
|
||||
|
@ -124,6 +128,8 @@ public:
|
|||
return _fullCount.value();
|
||||
}
|
||||
[[nodiscard]] rpl::producer<MuteRequest> toggleMuteRequests() const;
|
||||
[[nodiscard]] auto kickMemberRequests() const
|
||||
-> rpl::producer<not_null<UserData*>>;
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::unique_ptr<PeerListRow> createSelfRow() const;
|
||||
|
@ -155,8 +161,11 @@ private:
|
|||
uint64 _realId = 0;
|
||||
|
||||
rpl::event_stream<MuteRequest> _toggleMuteRequests;
|
||||
rpl::event_stream<not_null<UserData*>> _kickMemberRequests;
|
||||
rpl::variable<int> _fullCount = 1;
|
||||
Ui::BoxPointer _addBox;
|
||||
|
||||
not_null<QWidget*> _menuParent;
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
|
||||
//base::flat_map<not_null<UserData*>, crl::time> _repaintByTimer;
|
||||
//base::Timer _repaintTimer;
|
||||
|
@ -318,9 +327,12 @@ void Row::stopLastActionRipple() {
|
|||
}
|
||||
}
|
||||
|
||||
MembersController::MembersController(not_null<GroupCall*> call)
|
||||
MembersController::MembersController(
|
||||
not_null<GroupCall*> call,
|
||||
not_null<QWidget*> menuParent)
|
||||
: _call(call)
|
||||
, _channel(call->channel()) {
|
||||
, _channel(call->channel())
|
||||
, _menuParent(menuParent) {
|
||||
//, _repaintTimer([=] { repaintByTimer(); }) {
|
||||
setupListChangeViewers(call);
|
||||
}
|
||||
|
@ -586,25 +598,27 @@ void MembersController::loadMoreRows() {
|
|||
}
|
||||
|
||||
auto MembersController::toggleMuteRequests() const
|
||||
-> rpl::producer<GroupMembers::MuteRequest> {
|
||||
-> rpl::producer<MuteRequest> {
|
||||
return _toggleMuteRequests.events();
|
||||
}
|
||||
|
||||
auto MembersController::kickMemberRequests() const
|
||||
-> rpl::producer<not_null<UserData*>>{
|
||||
return _kickMemberRequests.events();
|
||||
}
|
||||
|
||||
void MembersController::rowClicked(not_null<PeerListRow*> row) {
|
||||
Ui::showPeerHistory(row->peer(), ShowAtUnreadMsgId);
|
||||
App::wnd()->activate();
|
||||
if (_menu) {
|
||||
_menu->deleteLater();
|
||||
_menu = nullptr;
|
||||
}
|
||||
_menu = rowContextMenu(_menuParent, row);
|
||||
_menu->popup(QCursor::pos());
|
||||
}
|
||||
|
||||
void MembersController::rowActionClicked(
|
||||
not_null<PeerListRow*> row) {
|
||||
Expects(row->peer()->isUser());
|
||||
|
||||
const auto real = static_cast<Row*>(row.get());
|
||||
const auto mute = (real->state() != Row::State::Muted);
|
||||
_toggleMuteRequests.fire(MuteRequest{
|
||||
.user = row->peer()->asUser(),
|
||||
.mute = mute,
|
||||
});
|
||||
rowClicked(row);
|
||||
}
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> MembersController::rowContextMenu(
|
||||
|
@ -612,8 +626,86 @@ base::unique_qptr<Ui::PopupMenu> MembersController::rowContextMenu(
|
|||
not_null<PeerListRow*> row) {
|
||||
Expects(row->peer()->isUser());
|
||||
|
||||
const auto real = static_cast<Row*>(row.get());
|
||||
const auto user = row->peer()->asUser();
|
||||
return nullptr;
|
||||
auto result = base::make_unique_q<Ui::PopupMenu>(
|
||||
parent,
|
||||
st::groupCallPopupMenu);
|
||||
|
||||
const auto mute = (real->state() != Row::State::Muted);
|
||||
const auto toggleMute = crl::guard(this, [=] {
|
||||
_toggleMuteRequests.fire(MuteRequest{
|
||||
.user = user,
|
||||
.mute = mute,
|
||||
});
|
||||
});
|
||||
|
||||
const auto session = &user->session();
|
||||
const auto getCurrentWindow = [=]() -> Window::SessionController* {
|
||||
if (const auto window = Core::App().activeWindow()) {
|
||||
if (const auto controller = window->sessionController()) {
|
||||
if (&controller->session() == session) {
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
const auto getWindow = [=] {
|
||||
if (const auto current = getCurrentWindow()) {
|
||||
return current;
|
||||
} else if (&Core::App().domain().active() != &session->account()) {
|
||||
Core::App().domain().activate(&session->account());
|
||||
}
|
||||
return getCurrentWindow();
|
||||
};
|
||||
const auto performOnMainWindow = [=](auto callback) {
|
||||
if (const auto window = getWindow()) {
|
||||
if (_menu) {
|
||||
_menu->discardParentReActivate();
|
||||
|
||||
// We must hide PopupMenu before we activate the MainWindow,
|
||||
// otherwise we set focus in field inside MainWindow and then
|
||||
// PopupMenu::hide activates back the group call panel :(
|
||||
_menu = nullptr;
|
||||
}
|
||||
callback(window);
|
||||
window->widget()->activate();
|
||||
}
|
||||
};
|
||||
const auto showProfile = [=] {
|
||||
performOnMainWindow([=](not_null<Window::SessionController*> window) {
|
||||
window->showPeerInfo(user);
|
||||
});
|
||||
};
|
||||
const auto showHistory = [=] {
|
||||
performOnMainWindow([=](not_null<Window::SessionController*> window) {
|
||||
window->showPeerHistory(user);
|
||||
});
|
||||
};
|
||||
const auto removeFromGroup = crl::guard(this, [=] {
|
||||
_kickMemberRequests.fire_copy(user);
|
||||
});
|
||||
|
||||
if (!user->isSelf() && _channel->canManageCall()) {
|
||||
result->addAction(
|
||||
(mute
|
||||
? tr::lng_group_call_context_mute(tr::now)
|
||||
: tr::lng_group_call_context_unmute(tr::now)),
|
||||
toggleMute);
|
||||
}
|
||||
result->addAction(
|
||||
tr::lng_context_view_profile(tr::now),
|
||||
showProfile);
|
||||
result->addAction(
|
||||
tr::lng_context_send_message(tr::now),
|
||||
showHistory);
|
||||
if (_channel->canRestrictUser(user)) {
|
||||
result->addAction(
|
||||
tr::lng_context_remove_from_group(tr::now),
|
||||
removeFromGroup);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListRow> MembersController::createSelfRow() const {
|
||||
|
@ -633,15 +725,16 @@ std::unique_ptr<PeerListRow> MembersController::createRow(
|
|||
} // namespace
|
||||
|
||||
GroupMembers::GroupMembers(
|
||||
QWidget *parent,
|
||||
not_null<QWidget*> parent,
|
||||
not_null<GroupCall*> call)
|
||||
: RpWidget(parent)
|
||||
, _call(call)
|
||||
, _scroll(this, st::defaultSolidScroll)
|
||||
, _listController(std::make_unique<MembersController>(call)) {
|
||||
, _listController(std::make_unique<MembersController>(call, parent)) {
|
||||
setupHeader(call);
|
||||
setupList();
|
||||
setContent(_list);
|
||||
setupFakeRoundCorners();
|
||||
_listController->setDelegate(static_cast<PeerListDelegate*>(this));
|
||||
|
||||
paintRequest(
|
||||
|
@ -660,6 +753,12 @@ auto GroupMembers::toggleMuteRequests() const
|
|||
_listController.get())->toggleMuteRequests();
|
||||
}
|
||||
|
||||
auto GroupMembers::kickMemberRequests() const
|
||||
-> rpl::producer<not_null<UserData*>> {
|
||||
return static_cast<MembersController*>(
|
||||
_listController.get())->kickMemberRequests();
|
||||
}
|
||||
|
||||
int GroupMembers::desiredHeight() const {
|
||||
auto desired = _header ? _header->height() : 0;
|
||||
auto count = [&] {
|
||||
|
@ -790,6 +889,10 @@ void GroupMembers::updateHeaderControlsGeometry(int newWidth) {
|
|||
_title->moveToLeft(0, 0);
|
||||
}
|
||||
|
||||
void GroupMembers::setupFakeRoundCorners() {
|
||||
|
||||
}
|
||||
|
||||
void GroupMembers::visibleTopBottomUpdated(
|
||||
int visibleTop,
|
||||
int visibleBottom) {
|
||||
|
|
|
@ -26,7 +26,7 @@ class GroupMembers final
|
|||
, private PeerListContentDelegate {
|
||||
public:
|
||||
GroupMembers(
|
||||
QWidget *parent,
|
||||
not_null<QWidget*> parent,
|
||||
not_null<GroupCall*> call);
|
||||
|
||||
struct MuteRequest {
|
||||
|
@ -37,6 +37,8 @@ public:
|
|||
[[nodiscard]] int desiredHeight() const;
|
||||
[[nodiscard]] rpl::producer<int> desiredHeightValue() const override;
|
||||
[[nodiscard]] rpl::producer<MuteRequest> toggleMuteRequests() const;
|
||||
[[nodiscard]] auto kickMemberRequests() const
|
||||
-> rpl::producer<not_null<UserData*>>;
|
||||
[[nodiscard]] rpl::producer<> addMembersRequests() const {
|
||||
return _addMemberRequests.events();
|
||||
}
|
||||
|
@ -68,6 +70,7 @@ private:
|
|||
void setupHeader(not_null<GroupCall*> call);
|
||||
object_ptr<Ui::FlatLabel> setupTitle(not_null<GroupCall*> call);
|
||||
void setupList();
|
||||
void setupFakeRoundCorners();
|
||||
|
||||
void setupButtons(not_null<GroupCall*> call);
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/event_filter.h"
|
||||
#include "boxes/peers/edit_participants_box.h"
|
||||
#include "app.h"
|
||||
#include "apiwrap.h" // api().kickParticipant.
|
||||
#include "styles/style_calls.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
|
@ -360,6 +361,11 @@ void GroupPanel::initWithCall(GroupCall *call) {
|
|||
}
|
||||
}, _callLifetime);
|
||||
|
||||
_members->kickMemberRequests(
|
||||
) | rpl::start_with_next([=](not_null<UserData*> user) {
|
||||
kickMember(user);
|
||||
}, _callLifetime);
|
||||
|
||||
_members->addMembersRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (_call) {
|
||||
|
@ -455,6 +461,43 @@ void GroupPanel::addMembers() {
|
|||
_layerBg->showBox(Box<PeerListBox>(std::move(controller), initBox));
|
||||
}
|
||||
|
||||
void GroupPanel::kickMember(not_null<UserData*> user) {
|
||||
_layerBg->showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
box->addRow(
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
box.get(),
|
||||
tr::lng_profile_sure_kick(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->firstName),
|
||||
st::groupCallBoxLabel),
|
||||
style::margins(
|
||||
st::boxRowPadding.left(),
|
||||
st::boxPadding.top(),
|
||||
st::boxRowPadding.right(),
|
||||
st::boxPadding.bottom()));
|
||||
box->addButton(tr::lng_box_remove(), [=] {
|
||||
box->closeBox();
|
||||
kickMemberSure(user);
|
||||
});
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}));
|
||||
}
|
||||
|
||||
void GroupPanel::kickMemberSure(not_null<UserData*> user) {
|
||||
const auto currentRestrictedRights = [&]() -> MTPChatBannedRights {
|
||||
const auto it = _channel->mgInfo->lastRestricted.find(user);
|
||||
return (it != _channel->mgInfo->lastRestricted.cend())
|
||||
? it->second.rights
|
||||
: MTP_chatBannedRights(MTP_flags(0), MTP_int(0));
|
||||
}();
|
||||
|
||||
_channel->session().api().kickParticipant(
|
||||
_channel,
|
||||
user,
|
||||
currentRestrictedRights);
|
||||
}
|
||||
|
||||
void GroupPanel::initLayout() {
|
||||
initGeometry();
|
||||
|
||||
|
|
|
@ -92,6 +92,8 @@ private:
|
|||
void hangup(bool discardCallChecked);
|
||||
|
||||
void addMembers();
|
||||
void kickMember(not_null<UserData*> user);
|
||||
void kickMemberSure(not_null<UserData*> user);
|
||||
[[nodiscard]] int computeMembersListTop() const;
|
||||
[[nodiscard]] std::optional<QRect> computeTitleRect() const;
|
||||
void refreshTitle();
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 79ea651127962fff366e9d76ce4d932490b30158
|
||||
Subproject commit e0fb1129d145054410476bd83d1cecf5c2a2644d
|
Loading…
Add table
Reference in a new issue