Allow inviting members in channel voice chats.

This commit is contained in:
John Preston 2021-03-15 22:40:59 +04:00
parent 2fddeb478b
commit 4659cc50f2
8 changed files with 225 additions and 171 deletions

View file

@ -37,7 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_session_controller.h" #include "window/window_session_controller.h"
#include "styles/style_calls.h" #include "styles/style_calls.h"
namespace Calls { namespace Calls::Group {
namespace { namespace {
constexpr auto kBlobsEnterDuration = crl::time(250); constexpr auto kBlobsEnterDuration = crl::time(250);
@ -1747,8 +1747,7 @@ std::unique_ptr<Row> MembersController::createInvitedRow(
} // namespace } // namespace
Members::Members(
GroupMembers::GroupMembers(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<GroupCall*> call) not_null<GroupCall*> call)
: RpWidget(parent) : RpWidget(parent)
@ -1762,25 +1761,25 @@ GroupMembers::GroupMembers(
_listController->setDelegate(static_cast<PeerListDelegate*>(this)); _listController->setDelegate(static_cast<PeerListDelegate*>(this));
} }
auto GroupMembers::toggleMuteRequests() const auto Members::toggleMuteRequests() const
-> rpl::producer<Group::MuteRequest> { -> rpl::producer<Group::MuteRequest> {
return static_cast<MembersController*>( return static_cast<MembersController*>(
_listController.get())->toggleMuteRequests(); _listController.get())->toggleMuteRequests();
} }
auto GroupMembers::changeVolumeRequests() const auto Members::changeVolumeRequests() const
-> rpl::producer<Group::VolumeRequest> { -> rpl::producer<Group::VolumeRequest> {
return static_cast<MembersController*>( return static_cast<MembersController*>(
_listController.get())->changeVolumeRequests(); _listController.get())->changeVolumeRequests();
} }
auto GroupMembers::kickParticipantRequests() const auto Members::kickParticipantRequests() const
-> rpl::producer<not_null<PeerData*>> { -> rpl::producer<not_null<PeerData*>> {
return static_cast<MembersController*>( return static_cast<MembersController*>(
_listController.get())->kickParticipantRequests(); _listController.get())->kickParticipantRequests();
} }
int GroupMembers::desiredHeight() const { int Members::desiredHeight() const {
const auto top = _addMember ? _addMember->height() : 0; const auto top = _addMember ? _addMember->height() : 0;
auto count = [&] { auto count = [&] {
if (const auto call = _call.get()) { if (const auto call = _call.get()) {
@ -1798,7 +1797,7 @@ int GroupMembers::desiredHeight() const {
+ (use ? st::lineWidth : 0); + (use ? st::lineWidth : 0);
} }
rpl::producer<int> GroupMembers::desiredHeightValue() const { rpl::producer<int> Members::desiredHeightValue() const {
const auto controller = static_cast<MembersController*>( const auto controller = static_cast<MembersController*>(
_listController.get()); _listController.get());
return rpl::combine( return rpl::combine(
@ -1810,12 +1809,28 @@ rpl::producer<int> GroupMembers::desiredHeightValue() const {
}); });
} }
void GroupMembers::setupAddMember(not_null<GroupCall*> call) { void Members::setupAddMember(not_null<GroupCall*> call) {
using namespace rpl::mappers; using namespace rpl::mappers;
const auto peer = call->peer(); const auto peer = call->peer();
if (peer->isBroadcast()) { if (const auto channel = peer->asBroadcast()) {
_canAddMembers = false; _canAddMembers = rpl::single(
false
) | rpl::then(peer->session().changes().peerFlagsValue(
peer,
Data::PeerUpdate::Flag::GroupCall
) | rpl::map([=] {
return peer->groupCall();
}) | rpl::filter([=](Data::GroupCall *real) {
const auto call = _call.get();
return call && real && (real->id() == call->id());
}) | rpl::take(
1
) | rpl::map([=] {
return Data::PeerFlagValue(
channel,
MTPDchannel::Flag::f_username);
}) | rpl::flatten_latest());
} else { } else {
_canAddMembers = Data::CanWriteValue(peer.get()); _canAddMembers = Data::CanWriteValue(peer.get());
SubscribeToMigration( SubscribeToMigration(
@ -1851,12 +1866,12 @@ void GroupMembers::setupAddMember(not_null<GroupCall*> call) {
}, lifetime()); }, lifetime());
} }
rpl::producer<int> GroupMembers::fullCountValue() const { rpl::producer<int> Members::fullCountValue() const {
return static_cast<MembersController*>( return static_cast<MembersController*>(
_listController.get())->fullCountValue(); _listController.get())->fullCountValue();
} }
void GroupMembers::setupList() { void Members::setupList() {
_listController->setStyleOverrides(&st::groupCallMembersList); _listController->setStyleOverrides(&st::groupCallMembersList);
_list = _scroll->setOwnedWidget(object_ptr<ListWidget>( _list = _scroll->setOwnedWidget(object_ptr<ListWidget>(
this, this,
@ -1877,11 +1892,11 @@ void GroupMembers::setupList() {
updateControlsGeometry(); updateControlsGeometry();
} }
void GroupMembers::resizeEvent(QResizeEvent *e) { void Members::resizeEvent(QResizeEvent *e) {
updateControlsGeometry(); updateControlsGeometry();
} }
void GroupMembers::resizeToList() { void Members::resizeToList() {
if (!_list) { if (!_list) {
return; return;
} }
@ -1898,7 +1913,7 @@ void GroupMembers::resizeToList() {
} }
} }
void GroupMembers::updateControlsGeometry() { void Members::updateControlsGeometry() {
if (!_list) { if (!_list) {
return; return;
} }
@ -1912,7 +1927,7 @@ void GroupMembers::updateControlsGeometry() {
_list->resizeToWidth(width()); _list->resizeToWidth(width());
} }
void GroupMembers::setupFakeRoundCorners() { void Members::setupFakeRoundCorners() {
const auto size = st::roundRadiusLarge; const auto size = st::roundRadiusLarge;
const auto full = 3 * size; const auto full = 3 * size;
const auto imagePartSize = size * cIntRetinaFactor(); const auto imagePartSize = size * cIntRetinaFactor();
@ -1975,40 +1990,40 @@ void GroupMembers::setupFakeRoundCorners() {
}, lifetime()); }, lifetime());
} }
void GroupMembers::peerListSetTitle(rpl::producer<QString> title) { void Members::peerListSetTitle(rpl::producer<QString> title) {
} }
void GroupMembers::peerListSetAdditionalTitle(rpl::producer<QString> title) { void Members::peerListSetAdditionalTitle(rpl::producer<QString> title) {
} }
void GroupMembers::peerListSetHideEmpty(bool hide) { void Members::peerListSetHideEmpty(bool hide) {
} }
bool GroupMembers::peerListIsRowChecked(not_null<PeerListRow*> row) { bool Members::peerListIsRowChecked(not_null<PeerListRow*> row) {
return false; return false;
} }
void GroupMembers::peerListScrollToTop() { void Members::peerListScrollToTop() {
} }
int GroupMembers::peerListSelectedRowsCount() { int Members::peerListSelectedRowsCount() {
return 0; return 0;
} }
void GroupMembers::peerListAddSelectedPeerInBunch(not_null<PeerData*> peer) { void Members::peerListAddSelectedPeerInBunch(not_null<PeerData*> peer) {
Unexpected("Item selection in Calls::GroupMembers."); Unexpected("Item selection in Calls::Members.");
} }
void GroupMembers::peerListAddSelectedRowInBunch(not_null<PeerListRow*> row) { void Members::peerListAddSelectedRowInBunch(not_null<PeerListRow*> row) {
Unexpected("Item selection in Calls::GroupMembers."); Unexpected("Item selection in Calls::Members.");
} }
void GroupMembers::peerListFinishSelectedRowsBunch() { void Members::peerListFinishSelectedRowsBunch() {
} }
void GroupMembers::peerListSetDescription( void Members::peerListSetDescription(
object_ptr<Ui::FlatLabel> description) { object_ptr<Ui::FlatLabel> description) {
description.destroy(); description.destroy();
} }
} // namespace Calls } // namespace Calls::Group

View file

@ -19,19 +19,19 @@ class GroupCall;
} // namespace Data } // namespace Data
namespace Calls { namespace Calls {
class GroupCall;
} // namespace Calls
namespace Calls::Group {
namespace Group {
struct VolumeRequest; struct VolumeRequest;
struct MuteRequest; struct MuteRequest;
} // namespace Group
class GroupCall; class Members final
class GroupMembers final
: public Ui::RpWidget : public Ui::RpWidget
, private PeerListContentDelegate { , private PeerListContentDelegate {
public: public:
GroupMembers( Members(
not_null<QWidget*> parent, not_null<QWidget*> parent,
not_null<GroupCall*> call); not_null<GroupCall*> call);

View file

@ -49,7 +49,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include <QtGui/QWindow> #include <QtGui/QWindow>
namespace Calls { namespace Calls::Group {
namespace { namespace {
constexpr auto kSpacePushToTalkDelay = crl::time(250); constexpr auto kSpacePushToTalkDelay = crl::time(250);
@ -247,7 +247,7 @@ std::unique_ptr<PeerListRow> InviteContactsController::createRow(
} // namespace } // namespace
GroupPanel::GroupPanel(not_null<GroupCall*> call) Panel::Panel(not_null<GroupCall*> call)
: _call(call) : _call(call)
, _peer(call->peer()) , _peer(call->peer())
, _window(std::make_unique<Ui::Window>(Core::App().getModalParent())) , _window(std::make_unique<Ui::Window>(Core::App().getModalParent()))
@ -308,13 +308,13 @@ GroupPanel::GroupPanel(not_null<GroupCall*> call)
}, widget()->lifetime()); }, widget()->lifetime());
} }
GroupPanel::~GroupPanel() { Panel::~Panel() {
if (_menu) { if (_menu) {
_menu.destroy(); _menu.destroy();
} }
} }
void GroupPanel::setupRealCallViewers(not_null<GroupCall*> call) { void Panel::setupRealCallViewers(not_null<GroupCall*> call) {
const auto peer = call->peer(); const auto peer = call->peer();
peer->session().changes().peerFlagsValue( peer->session().changes().peerFlagsValue(
peer, peer,
@ -330,21 +330,21 @@ void GroupPanel::setupRealCallViewers(not_null<GroupCall*> call) {
}, _window->lifetime()); }, _window->lifetime());
} }
bool GroupPanel::isActive() const { bool Panel::isActive() const {
return _window->isActiveWindow() return _window->isActiveWindow()
&& _window->isVisible() && _window->isVisible()
&& !(_window->windowState() & Qt::WindowMinimized); && !(_window->windowState() & Qt::WindowMinimized);
} }
void GroupPanel::minimize() { void Panel::minimize() {
_window->setWindowState(_window->windowState() | Qt::WindowMinimized); _window->setWindowState(_window->windowState() | Qt::WindowMinimized);
} }
void GroupPanel::close() { void Panel::close() {
_window->close(); _window->close();
} }
void GroupPanel::showAndActivate() { void Panel::showAndActivate() {
if (_window->isHidden()) { if (_window->isHidden()) {
_window->show(); _window->show();
} }
@ -357,7 +357,7 @@ void GroupPanel::showAndActivate() {
_window->setFocus(); _window->setFocus();
} }
void GroupPanel::migrate(not_null<ChannelData*> channel) { void Panel::migrate(not_null<ChannelData*> channel) {
_peer = channel; _peer = channel;
_peerLifetime.destroy(); _peerLifetime.destroy();
subscribeToPeerChanges(); subscribeToPeerChanges();
@ -365,7 +365,7 @@ void GroupPanel::migrate(not_null<ChannelData*> channel) {
refreshTitle(); refreshTitle();
} }
void GroupPanel::subscribeToPeerChanges() { void Panel::subscribeToPeerChanges() {
Info::Profile::NameValue( Info::Profile::NameValue(
_peer _peer
) | rpl::start_with_next([=](const TextWithEntities &name) { ) | rpl::start_with_next([=](const TextWithEntities &name) {
@ -373,7 +373,7 @@ void GroupPanel::subscribeToPeerChanges() {
}, _peerLifetime); }, _peerLifetime);
} }
void GroupPanel::initWindow() { void Panel::initWindow() {
_window->setAttribute(Qt::WA_OpaquePaintEvent); _window->setAttribute(Qt::WA_OpaquePaintEvent);
_window->setAttribute(Qt::WA_NoSystemBackground); _window->setAttribute(Qt::WA_NoSystemBackground);
_window->setWindowIcon( _window->setWindowIcon(
@ -412,7 +412,7 @@ void GroupPanel::initWindow() {
}); });
} }
void GroupPanel::initWidget() { void Panel::initWidget() {
widget()->setMouseTracking(true); widget()->setMouseTracking(true);
widget()->paintRequest( widget()->paintRequest(
@ -430,7 +430,7 @@ void GroupPanel::initWidget() {
}, widget()->lifetime()); }, widget()->lifetime());
} }
void GroupPanel::endCall() { void Panel::endCall() {
if (!_call) { if (!_call) {
return; return;
} else if (!_call->peer()->canManageGroupCall()) { } else if (!_call->peer()->canManageGroupCall()) {
@ -438,13 +438,13 @@ void GroupPanel::endCall() {
return; return;
} }
_layerBg->showBox(Box( _layerBg->showBox(Box(
Group::LeaveBox, LeaveBox,
_call, _call,
false, false,
Group::BoxContext::GroupCallPanel)); BoxContext::GroupCallPanel));
} }
void GroupPanel::initControls() { void Panel::initControls() {
_mute->clicks( _mute->clicks(
) | rpl::filter([=](Qt::MouseButton button) { ) | rpl::filter([=](Qt::MouseButton button) {
return (button == Qt::LeftButton) && (_call != nullptr); return (button == Qt::LeftButton) && (_call != nullptr);
@ -463,7 +463,7 @@ void GroupPanel::initControls() {
_hangup->setClickedCallback([=] { endCall(); }); _hangup->setClickedCallback([=] { endCall(); });
_settings->setClickedCallback([=] { _settings->setClickedCallback([=] {
if (_call) { if (_call) {
_layerBg->showBox(Box(Group::SettingsBox, _call)); _layerBg->showBox(Box(SettingsBox, _call));
} }
}); });
@ -478,7 +478,7 @@ void GroupPanel::initControls() {
initWithCall(_call); initWithCall(_call);
} }
void GroupPanel::initWithCall(GroupCall *call) { void Panel::initWithCall(GroupCall *call) {
_callLifetime.destroy(); _callLifetime.destroy();
_call = call; _call = call;
if (!_call) { if (!_call) {
@ -505,14 +505,14 @@ void GroupPanel::initWithCall(GroupCall *call) {
}, _callLifetime); }, _callLifetime);
_members->toggleMuteRequests( _members->toggleMuteRequests(
) | rpl::start_with_next([=](Group::MuteRequest request) { ) | rpl::start_with_next([=](MuteRequest request) {
if (_call) { if (_call) {
_call->toggleMute(request); _call->toggleMute(request);
} }
}, _callLifetime); }, _callLifetime);
_members->changeVolumeRequests( _members->changeVolumeRequests(
) | rpl::start_with_next([=](Group::VolumeRequest request) { ) | rpl::start_with_next([=](VolumeRequest request) {
if (_call) { if (_call) {
_call->changeVolume(request); _call->changeVolume(request);
} }
@ -525,10 +525,27 @@ void GroupPanel::initWithCall(GroupCall *call) {
} }
}, _callLifetime); }, _callLifetime);
const auto showBox = [=](object_ptr<Ui::BoxContent> next) {
_layerBg->showBox(std::move(next));
};
const auto showToast = [=](QString text) {
Ui::Toast::Show(widget(), text);
};
auto [shareLinkCallback, shareLinkLifetime] = ShareInviteLinkAction(
_peer,
showBox,
showToast);
auto shareLink = std::move(shareLinkCallback);
_members->lifetime().add(std::move(shareLinkLifetime));
_members->addMembersRequests( _members->addMembersRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {
if (_call) { if (_call) {
addMembers(); if (_peer->isBroadcast() && _peer->asChannel()->hasUsername()) {
shareLink();
} else {
addMembers();
}
} }
}, _callLifetime); }, _callLifetime);
@ -574,7 +591,7 @@ void GroupPanel::initWithCall(GroupCall *call) {
}, _callLifetime); }, _callLifetime);
} }
void GroupPanel::subscribeToChanges(not_null<Data::GroupCall*> real) { void Panel::subscribeToChanges(not_null<Data::GroupCall*> real) {
_titleText = real->titleValue(); _titleText = real->titleValue();
const auto validateRecordingMark = [=](bool recording) { const auto validateRecordingMark = [=](bool recording) {
@ -634,7 +651,7 @@ void GroupPanel::subscribeToChanges(not_null<Data::GroupCall*> real) {
rpl::single( rpl::single(
_call->joinAs() _call->joinAs()
) | rpl::then(_call->rejoinEvents( ) | rpl::then(_call->rejoinEvents(
) | rpl::map([](const Group::RejoinEvent &event) { ) | rpl::map([](const RejoinEvent &event) {
return event.nowJoinAs; return event.nowJoinAs;
})) | rpl::start_with_next([=](not_null<PeerData*> joinAs) { })) | rpl::start_with_next([=](not_null<PeerData*> joinAs) {
auto joinAsToggle = object_ptr<Ui::UserpicButton>( auto joinAsToggle = object_ptr<Ui::UserpicButton>(
@ -656,9 +673,9 @@ void GroupPanel::subscribeToChanges(not_null<Data::GroupCall*> real) {
updateControlsGeometry(); updateControlsGeometry();
} }
void GroupPanel::chooseJoinAs() { void Panel::chooseJoinAs() {
const auto context = Group::ChooseJoinAsProcess::Context::Switch; const auto context = ChooseJoinAsProcess::Context::Switch;
const auto callback = [=](Group::JoinInfo info) { const auto callback = [=](JoinInfo info) {
if (_call) { if (_call) {
_call->rejoinAs(info); _call->rejoinAs(info);
} }
@ -678,12 +695,12 @@ void GroupPanel::chooseJoinAs() {
_call->joinAs()); _call->joinAs());
} }
void GroupPanel::showMainMenu() { void Panel::showMainMenu() {
if (_menu || !_call) { if (_menu || !_call) {
return; return;
} }
_menu.create(widget(), st::groupCallDropdownMenu); _menu.create(widget(), st::groupCallDropdownMenu);
Group::FillMenu( FillMenu(
_menu.data(), _menu.data(),
_peer, _peer,
_call, _call,
@ -725,7 +742,7 @@ void GroupPanel::showMainMenu() {
} }
} }
void GroupPanel::addMembers() { void Panel::addMembers() {
const auto real = _peer->groupCall(); const auto real = _peer->groupCall();
if (!_call || !real || real->id() != _call->id()) { if (!_call || !real || real->id() != _call->id()) {
return; return;
@ -825,7 +842,7 @@ void GroupPanel::addMembers() {
finish(); finish();
}; };
auto box = Box( auto box = Box(
Group::ConfirmBox, ConfirmBox,
TextWithEntities{ text }, TextWithEntities{ text },
tr::lng_participant_invite(), tr::lng_participant_invite(),
[=] { inviteWithAdd(users, nonMembers, finishWithConfirm); }); [=] { inviteWithAdd(users, nonMembers, finishWithConfirm); });
@ -866,7 +883,7 @@ void GroupPanel::addMembers() {
_layerBg->showBox(Box<PeerListsBox>(std::move(controllers), initBox)); _layerBg->showBox(Box<PeerListsBox>(std::move(controllers), initBox));
} }
void GroupPanel::kickMember(not_null<UserData*> user) { void Panel::kickMember(not_null<UserData*> user) {
_layerBg->showBox(Box([=](not_null<Ui::GenericBox*> box) { _layerBg->showBox(Box([=](not_null<Ui::GenericBox*> box) {
box->addRow( box->addRow(
object_ptr<Ui::FlatLabel>( object_ptr<Ui::FlatLabel>(
@ -889,7 +906,7 @@ void GroupPanel::kickMember(not_null<UserData*> user) {
})); }));
} }
void GroupPanel::kickMemberSure(not_null<UserData*> user) { void Panel::kickMemberSure(not_null<UserData*> user) {
if (const auto chat = _peer->asChat()) { if (const auto chat = _peer->asChat()) {
chat->session().api().kickParticipant(chat, user); chat->session().api().kickParticipant(chat, user);
} else if (const auto channel = _peer->asChannel()) { } else if (const auto channel = _peer->asChannel()) {
@ -907,7 +924,7 @@ void GroupPanel::kickMemberSure(not_null<UserData*> user) {
} }
} }
void GroupPanel::initLayout() { void Panel::initLayout() {
initGeometry(); initGeometry();
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
@ -922,18 +939,18 @@ void GroupPanel::initLayout() {
#endif // !Q_OS_MAC #endif // !Q_OS_MAC
} }
void GroupPanel::showControls() { void Panel::showControls() {
Expects(_call != nullptr); Expects(_call != nullptr);
widget()->showChildren(); widget()->showChildren();
} }
void GroupPanel::closeBeforeDestroy() { void Panel::closeBeforeDestroy() {
_window->close(); _window->close();
initWithCall(nullptr); initWithCall(nullptr);
} }
void GroupPanel::initGeometry() { void Panel::initGeometry() {
const auto center = Core::App().getPointForCallPanelCenter(); const auto center = Core::App().getPointForCallPanelCenter();
const auto rect = QRect(0, 0, st::groupCallWidth, st::groupCallHeight); const auto rect = QRect(0, 0, st::groupCallWidth, st::groupCallHeight);
_window->setGeometry(rect.translated(center - rect.center())); _window->setGeometry(rect.translated(center - rect.center()));
@ -942,7 +959,7 @@ void GroupPanel::initGeometry() {
updateControlsGeometry(); updateControlsGeometry();
} }
QRect GroupPanel::computeTitleRect() const { QRect Panel::computeTitleRect() const {
const auto skip = st::groupCallTitleTop; const auto skip = st::groupCallTitleTop;
const auto remove = skip + (_menuToggle const auto remove = skip + (_menuToggle
? (_menuToggle->width() + st::groupCallMenuTogglePosition.x()) ? (_menuToggle->width() + st::groupCallMenuTogglePosition.x())
@ -961,7 +978,7 @@ QRect GroupPanel::computeTitleRect() const {
#endif // !Q_OS_MAC #endif // !Q_OS_MAC
} }
void GroupPanel::updateControlsGeometry() { void Panel::updateControlsGeometry() {
if (widget()->size().isEmpty()) { if (widget()->size().isEmpty()) {
return; return;
} }
@ -1019,7 +1036,7 @@ void GroupPanel::updateControlsGeometry() {
} }
} }
void GroupPanel::refreshTitle() { void Panel::refreshTitle() {
if (!_title) { if (!_title) {
auto text = rpl::combine( auto text = rpl::combine(
Info::Profile::NameValue(_peer), Info::Profile::NameValue(_peer),
@ -1060,7 +1077,7 @@ void GroupPanel::refreshTitle() {
top); top);
} }
void GroupPanel::refreshTitleGeometry() { void Panel::refreshTitleGeometry() {
if (!_title) { if (!_title) {
return; return;
} }
@ -1099,7 +1116,7 @@ void GroupPanel::refreshTitleGeometry() {
} }
} }
void GroupPanel::paint(QRect clip) { void Panel::paint(QRect clip) {
Painter p(widget()); Painter p(widget());
auto region = QRegion(clip); auto region = QRegion(clip);
@ -1108,7 +1125,7 @@ void GroupPanel::paint(QRect clip) {
} }
} }
bool GroupPanel::handleClose() { bool Panel::handleClose() {
if (_call) { if (_call) {
_window->hide(); _window->hide();
return true; return true;
@ -1116,8 +1133,8 @@ bool GroupPanel::handleClose() {
return false; return false;
} }
not_null<Ui::RpWidget*> GroupPanel::widget() const { not_null<Ui::RpWidget*> Panel::widget() const {
return _window->body(); return _window->body();
} }
} // namespace Calls } // namespace Calls::Group

View file

@ -48,17 +48,14 @@ struct CallSignalBars;
struct CallBodyLayout; struct CallBodyLayout;
} // namespace style } // namespace style
namespace Calls { namespace Calls::Group {
class Userpic; class Members;
class SignalBars;
class GroupMembers; class Panel final {
class GroupPanel final {
public: public:
GroupPanel(not_null<GroupCall*> call); Panel(not_null<GroupCall*> call);
~GroupPanel(); ~Panel();
[[nodiscard]] bool isActive() const; [[nodiscard]] bool isActive() const;
void minimize(); void minimize();
@ -119,9 +116,9 @@ private:
object_ptr<Ui::IconButton> _menuToggle = { nullptr }; object_ptr<Ui::IconButton> _menuToggle = { nullptr };
object_ptr<Ui::DropdownMenu> _menu = { nullptr }; object_ptr<Ui::DropdownMenu> _menu = { nullptr };
object_ptr<Ui::AbstractButton> _joinAsToggle = { nullptr }; object_ptr<Ui::AbstractButton> _joinAsToggle = { nullptr };
object_ptr<GroupMembers> _members; object_ptr<Members> _members;
rpl::variable<QString> _titleText; rpl::variable<QString> _titleText;
Group::ChooseJoinAsProcess _joinAsProcess; ChooseJoinAsProcess _joinAsProcess;
object_ptr<Ui::CallButton> _settings; object_ptr<Ui::CallButton> _settings;
std::unique_ptr<Ui::CallMuteButton> _mute; std::unique_ptr<Ui::CallMuteButton> _mute;
@ -131,4 +128,4 @@ private:
}; };
} // namespace Calls } // namespace Calls::Group

View file

@ -216,14 +216,6 @@ void SettingsBox(
const auto weakBox = Ui::MakeWeak(box); const auto weakBox = Ui::MakeWeak(box);
struct State { struct State {
State(not_null<Main::Session*> session) : session(session) {
}
~State() {
session->api().request(linkListenerRequestId).cancel();
session->api().request(linkSpeakerRequestId).cancel();
}
not_null<Main::Session*> session;
rpl::event_stream<QString> outputNameStream; rpl::event_stream<QString> outputNameStream;
rpl::event_stream<QString> inputNameStream; rpl::event_stream<QString> inputNameStream;
std::unique_ptr<Webrtc::AudioInputTester> micTester; std::unique_ptr<Webrtc::AudioInputTester> micTester;
@ -231,14 +223,10 @@ void SettingsBox(
float micLevel = 0.; float micLevel = 0.;
Ui::Animations::Simple micLevelAnimation; Ui::Animations::Simple micLevelAnimation;
base::Timer levelUpdateTimer; base::Timer levelUpdateTimer;
std::optional<QString> linkSpeaker;
QString linkListener;
bool generatingLink = false; bool generatingLink = false;
mtpRequestId linkListenerRequestId = 0;
mtpRequestId linkSpeakerRequestId = 0;
}; };
const auto peer = call->peer(); const auto peer = call->peer();
const auto state = box->lifetime().make_state<State>(&peer->session()); const auto state = box->lifetime().make_state<State>();
const auto real = peer->groupCall(); const auto real = peer->groupCall();
const auto id = call->id(); const auto id = call->id();
const auto goodReal = (real && real->id() == id); const auto goodReal = (real && real->id() == id);
@ -538,74 +526,25 @@ void SettingsBox(
//AddDivider(layout); //AddDivider(layout);
//AddSkip(layout); //AddSkip(layout);
if (!peer->canManageGroupCall()) {
state->linkSpeaker = QString();
}
auto shareLink = Fn<void()>(); auto shareLink = Fn<void()>();
if (peer->isChannel() if (peer->isChannel()
&& peer->asChannel()->hasUsername() && peer->asChannel()->hasUsername()
&& goodReal) { && goodReal) {
const auto input = real->input(); const auto showBox = crl::guard(box, [=](
const auto shareReady = [=] { object_ptr<Ui::BoxContent> box) {
if (!state->linkSpeaker.has_value() box->getDelegate()->show(std::move(box));
|| state->linkListener.isEmpty()) { });
return false; const auto showToast = crl::guard(box, [=](QString text) {
} Ui::Toast::Show(
const auto showToast = crl::guard(box, [=](QString text) { box->getDelegate()->outerContainer(),
Ui::Toast::Show( text);
box->getDelegate()->outerContainer(), });
text); auto [shareLinkCallback, shareLinkLifetime] = ShareInviteLinkAction(
}); peer,
box->getDelegate()->show(ShareInviteLinkBox( showBox,
peer, showToast);
*state->linkSpeaker, shareLink = std::move(shareLinkCallback);
state->linkListener, box->lifetime().add(std::move(shareLinkLifetime));
showToast));
return true;
};
shareLink = [=] {
if (shareReady() || state->generatingLink) {
return;
}
state->generatingLink = true;
state->linkListenerRequestId = peer->session().api().request(
MTPphone_ExportGroupCallInvite(
MTP_flags(0),
input
)
).done(crl::guard(box, [=](
const MTPphone_ExportedGroupCallInvite &result) {
state->linkListenerRequestId = 0;
result.match([&](
const MTPDphone_exportedGroupCallInvite &data) {
state->linkListener = qs(data.vlink());
shareReady();
});
})).send();
if (!state->linkSpeaker.has_value()) {
using Flag = MTPphone_ExportGroupCallInvite::Flag;
state->linkSpeakerRequestId = peer->session().api().request(
MTPphone_ExportGroupCallInvite(
MTP_flags(Flag::f_can_self_unmute),
input
)).done(crl::guard(box, [=](
const MTPphone_ExportedGroupCallInvite &result) {
state->linkSpeakerRequestId = 0;
result.match([&](
const MTPDphone_exportedGroupCallInvite &data) {
state->linkSpeaker = qs(data.vlink());
shareReady();
});
})).fail([=] {
state->linkSpeakerRequestId = 0;
state->linkSpeaker = QString();
shareReady();
}).send();
}
};
} else { } else {
const auto lookupLink = [=] { const auto lookupLink = [=] {
if (const auto group = peer->asMegagroup()) { if (const auto group = peer->asMegagroup()) {
@ -698,4 +637,85 @@ void SettingsBox(
}); });
} }
std::pair<Fn<void()>, rpl::lifetime> ShareInviteLinkAction(
not_null<PeerData*> peer,
Fn<void(object_ptr<Ui::BoxContent>)> showBox,
Fn<void(QString)> showToast) {
auto lifetime = rpl::lifetime();
struct State {
State(not_null<Main::Session*> session) : session(session) {
}
~State() {
session->api().request(linkListenerRequestId).cancel();
session->api().request(linkSpeakerRequestId).cancel();
}
not_null<Main::Session*> session;
std::optional<QString> linkSpeaker;
QString linkListener;
mtpRequestId linkListenerRequestId = 0;
mtpRequestId linkSpeakerRequestId = 0;
bool generatingLink = false;
};
const auto state = lifetime.make_state<State>(&peer->session());
if (!peer->canManageGroupCall()) {
state->linkSpeaker = QString();
}
const auto shareReady = [=] {
if (!state->linkSpeaker.has_value()
|| state->linkListener.isEmpty()) {
return false;
}
showBox(ShareInviteLinkBox(
peer,
*state->linkSpeaker,
state->linkListener,
showToast));
return true;
};
auto callback = [=] {
const auto real = peer->groupCall();
if (shareReady() || state->generatingLink || !real) {
return;
}
state->generatingLink = true;
state->linkListenerRequestId = peer->session().api().request(
MTPphone_ExportGroupCallInvite(
MTP_flags(0),
real->input()
)
).done([=](const MTPphone_ExportedGroupCallInvite &result) {
state->linkListenerRequestId = 0;
result.match([&](
const MTPDphone_exportedGroupCallInvite &data) {
state->linkListener = qs(data.vlink());
shareReady();
});
}).send();
if (!state->linkSpeaker.has_value()) {
using Flag = MTPphone_ExportGroupCallInvite::Flag;
state->linkSpeakerRequestId = peer->session().api().request(
MTPphone_ExportGroupCallInvite(
MTP_flags(Flag::f_can_self_unmute),
real->input()
)).done([=](const MTPphone_ExportedGroupCallInvite &result) {
state->linkSpeakerRequestId = 0;
result.match([&](
const MTPDphone_exportedGroupCallInvite &data) {
state->linkSpeaker = qs(data.vlink());
shareReady();
});
}).fail([=] {
state->linkSpeakerRequestId = 0;
state->linkSpeaker = QString();
shareReady();
}).send();
}
};
return { std::move(callback), std::move(lifetime) };
}
} // namespace Calls::Group } // namespace Calls::Group

View file

@ -19,4 +19,9 @@ void SettingsBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
not_null<GroupCall*> call); not_null<GroupCall*> call);
[[nodiscard]] std::pair<Fn<void()>, rpl::lifetime> ShareInviteLinkAction(
not_null<PeerData*> peer,
Fn<void(object_ptr<Ui::BoxContent>)> showBox,
Fn<void(QString)> showToast);
} // namespace Calls::Group } // namespace Calls::Group

View file

@ -224,7 +224,7 @@ void Instance::createGroupCall(
destroyGroupCall(raw); destroyGroupCall(raw);
}, raw->lifetime()); }, raw->lifetime());
_currentGroupCallPanel = std::make_unique<GroupPanel>(raw); _currentGroupCallPanel = std::make_unique<Group::Panel>(raw);
_currentGroupCall = std::move(call); _currentGroupCall = std::move(call);
_currentGroupCallChanges.fire_copy(raw); _currentGroupCallChanges.fire_copy(raw);
} }

View file

@ -26,12 +26,12 @@ class Session;
namespace Calls::Group { namespace Calls::Group {
struct JoinInfo; struct JoinInfo;
class Panel;
} // namespace Calls::Group } // namespace Calls::Group
namespace Calls { namespace Calls {
class Panel; class Panel;
class GroupPanel;
class Instance class Instance
: private Call::Delegate : private Call::Delegate
@ -146,7 +146,7 @@ private:
std::unique_ptr<GroupCall> _currentGroupCall; std::unique_ptr<GroupCall> _currentGroupCall;
rpl::event_stream<GroupCall*> _currentGroupCallChanges; rpl::event_stream<GroupCall*> _currentGroupCallChanges;
std::unique_ptr<GroupPanel> _currentGroupCallPanel; std::unique_ptr<Group::Panel> _currentGroupCallPanel;
base::flat_map<QString, std::unique_ptr<Media::Audio::Track>> _tracks; base::flat_map<QString, std::unique_ptr<Media::Audio::Track>> _tracks;