mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-03 21:54:05 +02:00
Implement audio/video confcall invitations.
This commit is contained in:
parent
021115b463
commit
c5531b1bd8
15 changed files with 293 additions and 47 deletions
|
@ -4642,6 +4642,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_call_status_failed" = "failed to connect";
|
||||
"lng_call_status_ringing" = "ringing...";
|
||||
"lng_call_status_busy" = "line busy";
|
||||
"lng_call_status_group_invite" = "Telegram Group Call";
|
||||
"lng_call_status_sure" = "Click on the Camera icon if you want to start a video call.";
|
||||
"lng_call_fingerprint_tooltip" = "If the emoji on {user}'s screen are the same, this call is 100% secure";
|
||||
|
||||
|
|
|
@ -1543,6 +1543,26 @@ confcallJoinUserpics: UserpicsRow {
|
|||
invert: true;
|
||||
}
|
||||
confcallJoinUserpicsPadding: margins(0px, 0px, 0px, 16px);
|
||||
confcallInviteVideo: IconButton {
|
||||
width: 36px;
|
||||
height: 52px;
|
||||
|
||||
icon: icon {{ "info/info_media_video", groupCallMemberInactiveIcon }};
|
||||
iconOver: icon {{ "info/info_media_video", groupCallMemberInactiveIcon }};
|
||||
iconPosition: point(-1px, -1px);
|
||||
|
||||
ripple: groupCallRipple;
|
||||
rippleAreaPosition: point(0px, 8px);
|
||||
rippleAreaSize: 36px;
|
||||
}
|
||||
confcallInviteVideoActive: icon {{ "info/info_media_video", groupCallActiveFg }};
|
||||
confcallInviteVideoMargins: margins(0px, 0px, 10px, 0px);
|
||||
confcallInviteAudio: IconButton(confcallInviteVideo) {
|
||||
icon: icon {{ "menu/phone", groupCallMemberInactiveIcon }};
|
||||
iconOver: icon {{ "menu/phone", groupCallMemberInactiveIcon }};
|
||||
}
|
||||
confcallInviteAudioActive: icon {{ "menu/phone", groupCallActiveFg }};
|
||||
confcallInviteAudioMargins: margins(0px, 0px, 4px, 0px);
|
||||
|
||||
groupCallLinkBox: Box(confcallLinkBox) {
|
||||
bg: groupCallMembersBg;
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/random.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "calls/group/calls_group_common.h"
|
||||
#include "calls/calls_instance.h"
|
||||
#include "calls/calls_panel.h"
|
||||
#include "core/application.h"
|
||||
|
@ -251,7 +252,8 @@ Call::Call(
|
|||
not_null<Delegate*> delegate,
|
||||
not_null<UserData*> user,
|
||||
CallId conferenceId,
|
||||
MsgId conferenceInviteMsgId)
|
||||
MsgId conferenceInviteMsgId,
|
||||
bool video)
|
||||
: _delegate(delegate)
|
||||
, _user(user)
|
||||
, _api(&_user->session().mtp())
|
||||
|
@ -279,10 +281,10 @@ Call::Call(
|
|||
, _conferenceInviteMsgId(conferenceInviteMsgId)
|
||||
, _videoIncoming(
|
||||
std::make_unique<Webrtc::VideoTrack>(
|
||||
StartVideoState(false)))
|
||||
StartVideoState(video)))
|
||||
, _videoOutgoing(
|
||||
std::make_unique<Webrtc::VideoTrack>(
|
||||
StartVideoState(false))) {
|
||||
StartVideoState(video))) {
|
||||
startWaitingTrack();
|
||||
setupOutgoingVideo();
|
||||
}
|
||||
|
|
|
@ -106,7 +106,8 @@ public:
|
|||
not_null<Delegate*> delegate,
|
||||
not_null<UserData*> user,
|
||||
CallId conferenceId,
|
||||
MsgId conferenceInviteMsgId);
|
||||
MsgId conferenceInviteMsgId,
|
||||
bool video);
|
||||
|
||||
[[nodiscard]] Type type() const {
|
||||
return _type;
|
||||
|
|
|
@ -1010,6 +1010,7 @@ void Instance::showConferenceInvite(
|
|||
const auto media = item ? item->media() : nullptr;
|
||||
const auto call = media ? media->call() : nullptr;
|
||||
const auto conferenceId = call ? call->conferenceId : 0;
|
||||
const auto video = call->video;
|
||||
if (!conferenceId
|
||||
|| call->state != Data::CallState::Invitation
|
||||
|| user->isSelf()) {
|
||||
|
@ -1036,7 +1037,8 @@ void Instance::showConferenceInvite(
|
|||
delegate,
|
||||
user,
|
||||
conferenceId,
|
||||
conferenceInviteMsgId);
|
||||
conferenceInviteMsgId,
|
||||
video);
|
||||
const auto raw = call.get();
|
||||
|
||||
user->session().account().sessionChanges(
|
||||
|
|
|
@ -56,6 +56,7 @@ enum class CallType;
|
|||
class GroupCall;
|
||||
class Panel;
|
||||
struct DhConfig;
|
||||
struct InviteRequest;
|
||||
|
||||
struct StartGroupCallArgs {
|
||||
enum class JoinConfirm {
|
||||
|
@ -73,7 +74,7 @@ struct StartConferenceCallArgs {
|
|||
std::shared_ptr<TdE2E::Call> e2e;
|
||||
QString linkSlug;
|
||||
MsgId joinMessageId;
|
||||
std::vector<not_null<UserData*>> invite;
|
||||
std::vector<InviteRequest> invite;
|
||||
bool migrating = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -467,7 +467,7 @@ void Panel::initControls() {
|
|||
*creating = false;
|
||||
}
|
||||
};
|
||||
const auto create = [=](std::vector<not_null<UserData*>> users) {
|
||||
const auto create = [=](std::vector<InviteRequest> users) {
|
||||
if (*creating) {
|
||||
return;
|
||||
}
|
||||
|
@ -481,7 +481,7 @@ void Panel::initControls() {
|
|||
});
|
||||
};
|
||||
const auto invite = crl::guard(call, [=](
|
||||
std::vector<not_null<UserData*>> users) {
|
||||
std::vector<InviteRequest> users) {
|
||||
create(std::move(users));
|
||||
});
|
||||
const auto share = crl::guard(call, [=] {
|
||||
|
@ -1285,7 +1285,9 @@ void Panel::paint(QRect clip) {
|
|||
bool Panel::handleClose() const {
|
||||
if (_call) {
|
||||
if (_call->state() == Call::State::WaitingUserConfirmation
|
||||
|| _call->state() == Call::State::Busy) {
|
||||
|| _call->state() == Call::State::Busy
|
||||
|| _call->state() == Call::State::Starting
|
||||
|| _call->state() == Call::State::WaitingIncoming) {
|
||||
_call->hangup();
|
||||
} else {
|
||||
window()->hide();
|
||||
|
@ -1424,7 +1426,10 @@ void Panel::updateStatusText(State state) {
|
|||
case State::ExchangingKeys: return tr::lng_call_status_exchanging(tr::now);
|
||||
case State::Waiting: return tr::lng_call_status_waiting(tr::now);
|
||||
case State::Requesting: return tr::lng_call_status_requesting(tr::now);
|
||||
case State::WaitingIncoming: return tr::lng_call_status_incoming(tr::now);
|
||||
case State::WaitingIncoming:
|
||||
return (_call->conferenceInvite()
|
||||
? tr::lng_call_status_group_invite(tr::now)
|
||||
: tr::lng_call_status_incoming(tr::now));
|
||||
case State::Ringing: return tr::lng_call_status_ringing(tr::now);
|
||||
case State::Busy: return tr::lng_call_status_busy(tr::now);
|
||||
case State::WaitingUserConfirmation: return tr::lng_call_status_sure(tr::now);
|
||||
|
|
|
@ -3712,7 +3712,7 @@ void GroupCall::editParticipant(
|
|||
}
|
||||
|
||||
void GroupCall::inviteUsers(
|
||||
const std::vector<not_null<UserData*>> &users,
|
||||
const std::vector<InviteRequest> &requests,
|
||||
Fn<void(InviteResult)> done) {
|
||||
const auto real = lookupReal();
|
||||
if (!real) {
|
||||
|
@ -3737,9 +3737,11 @@ void GroupCall::inviteUsers(
|
|||
};
|
||||
|
||||
if (const auto call = _conferenceCall.get()) {
|
||||
for (const auto &user : users) {
|
||||
for (const auto &request : requests) {
|
||||
using Flag = MTPphone_InviteConferenceCallParticipant::Flag;
|
||||
const auto user = request.user;
|
||||
_api.request(MTPphone_InviteConferenceCallParticipant(
|
||||
MTP_flags(0),
|
||||
MTP_flags(request.video ? Flag::f_video : Flag()),
|
||||
inputCallSafe(),
|
||||
user->inputUser
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
|
@ -3785,7 +3787,8 @@ void GroupCall::inviteUsers(
|
|||
slice.clear();
|
||||
usersSlice.clear();
|
||||
};
|
||||
for (const auto &user : users) {
|
||||
for (const auto &request : requests) {
|
||||
const auto user = request.user;
|
||||
owner->registerInvitedToCallUser(_id, _peer, user);
|
||||
usersSlice.push_back(user);
|
||||
slice.push_back(user->inputUser);
|
||||
|
@ -3920,7 +3923,7 @@ void GroupCall::destroyScreencast() {
|
|||
}
|
||||
|
||||
TextWithEntities ComposeInviteResultToast(
|
||||
const GroupCall::InviteResult &result) {
|
||||
const InviteResult &result) {
|
||||
auto text = TextWithEntities();
|
||||
const auto invited = int(result.invited.size());
|
||||
const auto restricted = int(result.privacyRestricted.size());
|
||||
|
|
|
@ -60,6 +60,9 @@ enum class VideoQuality;
|
|||
enum class Error;
|
||||
} // namespace Group
|
||||
|
||||
struct InviteRequest;
|
||||
struct InviteResult;
|
||||
|
||||
enum class MuteState {
|
||||
Active,
|
||||
PushToTalk,
|
||||
|
@ -418,13 +421,8 @@ public:
|
|||
void toggleMute(const Group::MuteRequest &data);
|
||||
void changeVolume(const Group::VolumeRequest &data);
|
||||
|
||||
struct InviteResult {
|
||||
std::vector<not_null<UserData*>> invited;
|
||||
std::vector<not_null<UserData*>> alreadyIn;
|
||||
std::vector<not_null<UserData*>> privacyRestricted;
|
||||
};
|
||||
void inviteUsers(
|
||||
const std::vector<not_null<UserData*>> &users,
|
||||
const std::vector<InviteRequest> &requests,
|
||||
Fn<void(InviteResult)> done);
|
||||
|
||||
std::shared_ptr<GlobalShortcutManager> ensureGlobalShortcutManager();
|
||||
|
@ -754,6 +752,6 @@ private:
|
|||
};
|
||||
|
||||
[[nodiscard]] TextWithEntities ComposeInviteResultToast(
|
||||
const GroupCall::InviteResult &result);
|
||||
const InviteResult &result);
|
||||
|
||||
} // namespace Calls
|
||||
|
|
|
@ -41,6 +41,20 @@ namespace Window {
|
|||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Calls {
|
||||
|
||||
struct InviteRequest {
|
||||
not_null<UserData*> user;
|
||||
bool video = false;
|
||||
};
|
||||
struct InviteResult {
|
||||
std::vector<not_null<UserData*>> invited;
|
||||
std::vector<not_null<UserData*>> alreadyIn;
|
||||
std::vector<not_null<UserData*>> privacyRestricted;
|
||||
};
|
||||
|
||||
} // namespace Calls
|
||||
|
||||
namespace Calls::Group {
|
||||
|
||||
constexpr auto kDefaultVolume = 10000;
|
||||
|
@ -146,7 +160,7 @@ struct ConferenceCallLinkArgs {
|
|||
bool joining = false;
|
||||
bool migrating = false;
|
||||
Fn<void(QString)> finished;
|
||||
std::vector<not_null<UserData*>> invite;
|
||||
std::vector<InviteRequest> invite;
|
||||
ConferenceCallLinkStyleOverrides st;
|
||||
};
|
||||
void ShowConferenceCallLinkBox(
|
||||
|
@ -163,7 +177,7 @@ void ExportConferenceCallLink(
|
|||
struct ConferenceFactoryArgs {
|
||||
std::shared_ptr<Main::SessionShow> show;
|
||||
Fn<void(QString)> finished;
|
||||
std::vector<not_null<UserData*>> invite;
|
||||
std::vector<InviteRequest> invite;
|
||||
bool joining = false;
|
||||
bool migrating = false;
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "api/api_chat_participants.h"
|
||||
#include "calls/group/calls_group_call.h"
|
||||
#include "calls/group/calls_group_common.h"
|
||||
#include "calls/group/calls_group_menu.h"
|
||||
#include "calls/calls_call.h"
|
||||
#include "boxes/peer_lists_box.h"
|
||||
|
@ -19,10 +20,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "info/profile/info_profile_icon.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/session/session_show.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/painter.h"
|
||||
#include "apiwrap.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_boxes.h" // membersMarginTop
|
||||
|
@ -61,6 +64,36 @@ namespace {
|
|||
return result;
|
||||
}
|
||||
|
||||
class ConfInviteRow final : public PeerListRow {
|
||||
public:
|
||||
using PeerListRow::PeerListRow;
|
||||
|
||||
void setAlreadyIn(bool alreadyIn);
|
||||
void setVideo(bool video);
|
||||
|
||||
int elementsCount() const override;
|
||||
QRect elementGeometry(int element, int outerWidth) const override;
|
||||
bool elementDisabled(int element) const override;
|
||||
bool elementOnlySelect(int element) const override;
|
||||
void elementAddRipple(
|
||||
int element,
|
||||
QPoint point,
|
||||
Fn<void()> updateCallback) override;
|
||||
void elementsStopLastRipple() override;
|
||||
void elementsPaint(
|
||||
Painter &p,
|
||||
int outerWidth,
|
||||
bool selected,
|
||||
int selectedElement) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::RippleAnimation> _videoRipple;
|
||||
std::unique_ptr<Ui::RippleAnimation> _audioRipple;
|
||||
bool _alreadyIn = false;
|
||||
bool _video = false;
|
||||
|
||||
};
|
||||
|
||||
class ConfInviteController final : public ContactsBoxController {
|
||||
public:
|
||||
ConfInviteController(
|
||||
|
@ -69,6 +102,8 @@ public:
|
|||
Fn<void()> shareLink);
|
||||
|
||||
[[nodiscard]] rpl::producer<bool> hasSelectedValue() const;
|
||||
[[nodiscard]] std::vector<InviteRequest> requests(
|
||||
const std::vector<not_null<PeerData*>> &peers) const;
|
||||
|
||||
protected:
|
||||
void prepareViewHook() override;
|
||||
|
@ -77,16 +112,132 @@ protected:
|
|||
not_null<UserData*> user) override;
|
||||
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
void rowElementClicked(not_null<PeerListRow*> row, int element) override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] int fullCount() const;
|
||||
void toggleRowSelected(not_null<PeerListRow*> row, bool video);
|
||||
|
||||
const base::flat_set<not_null<UserData*>> _alreadyIn;
|
||||
const Fn<void()> _shareLink;
|
||||
rpl::variable<bool> _hasSelected;
|
||||
base::flat_set<not_null<UserData*>> _withVideo;
|
||||
bool _lastSelectWithVideo = false;
|
||||
|
||||
};
|
||||
|
||||
void ConfInviteRow::setAlreadyIn(bool alreadyIn) {
|
||||
_alreadyIn = alreadyIn;
|
||||
setDisabledState(alreadyIn ? State::DisabledChecked : State::Active);
|
||||
}
|
||||
|
||||
void ConfInviteRow::setVideo(bool video) {
|
||||
_video = video;
|
||||
}
|
||||
|
||||
int ConfInviteRow::elementsCount() const {
|
||||
return _alreadyIn ? 0 : 2;
|
||||
}
|
||||
|
||||
QRect ConfInviteRow::elementGeometry(int element, int outerWidth) const {
|
||||
if (_alreadyIn || (element != 1 && element != 2)) {
|
||||
return QRect();
|
||||
}
|
||||
const auto &st = (element == 1)
|
||||
? st::confcallInviteVideo
|
||||
: st::confcallInviteAudio;
|
||||
const auto size = QSize(st.width, st.height);
|
||||
const auto margins = (element == 1)
|
||||
? st::confcallInviteVideoMargins
|
||||
: st::confcallInviteAudioMargins;
|
||||
const auto right = margins.right();
|
||||
const auto top = margins.top();
|
||||
const auto side = (element == 1)
|
||||
? outerWidth
|
||||
: elementGeometry(1, outerWidth).x();
|
||||
const auto left = side - right - size.width();
|
||||
return QRect(QPoint(left, top), size);
|
||||
}
|
||||
|
||||
bool ConfInviteRow::elementDisabled(int element) const {
|
||||
return _alreadyIn
|
||||
|| (checked()
|
||||
&& ((_video && element == 1) || (!_video && element == 2)));
|
||||
}
|
||||
|
||||
bool ConfInviteRow::elementOnlySelect(int element) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConfInviteRow::elementAddRipple(
|
||||
int element,
|
||||
QPoint point,
|
||||
Fn<void()> updateCallback) {
|
||||
if (_alreadyIn || (element != 1 && element != 2)) {
|
||||
return;
|
||||
}
|
||||
auto &ripple = (element == 1) ? _videoRipple : _audioRipple;
|
||||
const auto &st = (element == 1)
|
||||
? st::confcallInviteVideo
|
||||
: st::confcallInviteAudio;
|
||||
if (!ripple) {
|
||||
auto mask = Ui::RippleAnimation::EllipseMask(QSize(
|
||||
st.rippleAreaSize,
|
||||
st.rippleAreaSize));
|
||||
ripple = std::make_unique<Ui::RippleAnimation>(
|
||||
st.ripple,
|
||||
std::move(mask),
|
||||
std::move(updateCallback));
|
||||
}
|
||||
ripple->add(point - st.rippleAreaPosition);
|
||||
}
|
||||
|
||||
void ConfInviteRow::elementsStopLastRipple() {
|
||||
if (_videoRipple) {
|
||||
_videoRipple->lastStop();
|
||||
}
|
||||
if (_audioRipple) {
|
||||
_audioRipple->lastStop();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfInviteRow::elementsPaint(
|
||||
Painter &p,
|
||||
int outerWidth,
|
||||
bool selected,
|
||||
int selectedElement) {
|
||||
if (_alreadyIn) {
|
||||
return;
|
||||
}
|
||||
const auto paintElement = [&](int element) {
|
||||
const auto &st = (element == 1)
|
||||
? st::confcallInviteVideo
|
||||
: st::confcallInviteAudio;
|
||||
auto &ripple = (element == 1) ? _videoRipple : _audioRipple;
|
||||
const auto active = checked() && ((element == 1) ? _video : !_video);
|
||||
const auto geometry = elementGeometry(element, outerWidth);
|
||||
if (ripple) {
|
||||
ripple->paint(
|
||||
p,
|
||||
geometry.x() + st.rippleAreaPosition.x(),
|
||||
geometry.y() + st.rippleAreaPosition.y(),
|
||||
outerWidth);
|
||||
if (ripple->empty()) {
|
||||
ripple.reset();
|
||||
}
|
||||
}
|
||||
const auto selected = (element == selectedElement);
|
||||
const auto &icon = active
|
||||
? (element == 1
|
||||
? st::confcallInviteVideoActive
|
||||
: st::confcallInviteAudioActive)
|
||||
: (selected ? st.iconOver : st.icon);
|
||||
icon.paintInCenter(p, geometry);
|
||||
};
|
||||
paintElement(1);
|
||||
paintElement(2);
|
||||
}
|
||||
|
||||
ConfInviteController::ConfInviteController(
|
||||
not_null<Main::Session*> session,
|
||||
base::flat_set<not_null<UserData*>> alreadyIn,
|
||||
|
@ -100,6 +251,18 @@ rpl::producer<bool> ConfInviteController::hasSelectedValue() const {
|
|||
return _hasSelected.value();
|
||||
}
|
||||
|
||||
std::vector<InviteRequest> ConfInviteController::requests(
|
||||
const std::vector<not_null<PeerData*>> &peers) const {
|
||||
auto result = std::vector<InviteRequest>();
|
||||
result.reserve(peers.size());
|
||||
for (const auto &peer : peers) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
result.push_back({ user, _withVideo.contains(user) });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<PeerListRow> ConfInviteController::createRow(
|
||||
not_null<UserData*> user) {
|
||||
if (user->isSelf()
|
||||
|
@ -108,9 +271,12 @@ std::unique_ptr<PeerListRow> ConfInviteController::createRow(
|
|||
|| user->isInaccessible()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto result = ContactsBoxController::createRow(user);
|
||||
auto result = std::make_unique<ConfInviteRow>(user);
|
||||
if (_alreadyIn.contains(user)) {
|
||||
result->setDisabledState(PeerListRow::State::DisabledChecked);
|
||||
result->setAlreadyIn(true);
|
||||
}
|
||||
if (_withVideo.contains(user)) {
|
||||
result->setVideo(true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -120,10 +286,42 @@ int ConfInviteController::fullCount() const {
|
|||
}
|
||||
|
||||
void ConfInviteController::rowClicked(not_null<PeerListRow*> row) {
|
||||
toggleRowSelected(row, _lastSelectWithVideo);
|
||||
}
|
||||
|
||||
void ConfInviteController::rowElementClicked(
|
||||
not_null<PeerListRow*> row,
|
||||
int element) {
|
||||
if (row->checked()) {
|
||||
static_cast<ConfInviteRow*>(row.get())->setVideo(element == 1);
|
||||
_lastSelectWithVideo = (element == 1);
|
||||
} else if (element == 1) {
|
||||
toggleRowSelected(row, true);
|
||||
} else if (element == 2) {
|
||||
toggleRowSelected(row, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfInviteController::toggleRowSelected(
|
||||
not_null<PeerListRow*> row,
|
||||
bool video) {
|
||||
auto count = fullCount();
|
||||
auto limit = Data::kMaxConferenceMembers;
|
||||
if (count < limit || row->checked()) {
|
||||
const auto real = static_cast<ConfInviteRow*>(row.get());
|
||||
if (!row->checked()) {
|
||||
real->setVideo(video);
|
||||
_lastSelectWithVideo = video;
|
||||
}
|
||||
const auto user = row->peer()->asUser();
|
||||
if (!row->checked() && video) {
|
||||
_withVideo.emplace(user);
|
||||
} else {
|
||||
_withVideo.remove(user);
|
||||
}
|
||||
delegate()->peerListSetRowChecked(row, !row->checked());
|
||||
|
||||
// row may have been destroyed here, from search.
|
||||
_hasSelected = (delegate()->peerListSelectedRowsCount() > 0);
|
||||
} else {
|
||||
delegate()->peerListUiShow()->showToast(
|
||||
|
@ -311,13 +509,7 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
|||
if (!call) {
|
||||
return;
|
||||
}
|
||||
auto peers = box->collectSelectedRows();
|
||||
auto users = ranges::views::all(
|
||||
peers
|
||||
) | ranges::views::transform([](not_null<PeerData*> peer) {
|
||||
return not_null(peer->asUser());
|
||||
}) | ranges::to_vector;
|
||||
const auto done = [=](GroupCall::InviteResult result) {
|
||||
const auto done = [=](InviteResult result) {
|
||||
(*close)();
|
||||
if (result.invited.empty()
|
||||
&& result.privacyRestricted.empty()) {
|
||||
|
@ -325,7 +517,9 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
|||
}
|
||||
showToast({ ComposeInviteResultToast(result) });
|
||||
};
|
||||
call->inviteUsers(users, done);
|
||||
call->inviteUsers(
|
||||
raw->requests(box->collectSelectedRows()),
|
||||
done);
|
||||
});
|
||||
}
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
|
@ -354,7 +548,12 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
|||
if (!call) {
|
||||
return;
|
||||
}
|
||||
call->inviteUsers(users, [=](GroupCall::InviteResult result) {
|
||||
auto requests = ranges::views::all(
|
||||
users
|
||||
) | ranges::views::transform([](not_null<UserData*> user) {
|
||||
return InviteRequest{ user };
|
||||
}) | ranges::to_vector;
|
||||
call->inviteUsers(std::move(requests), [=](InviteResult result) {
|
||||
if (result.invited.size() == 1) {
|
||||
showToast(tr::lng_group_call_invite_done_user(
|
||||
tr::now,
|
||||
|
@ -463,7 +662,7 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
|||
|
||||
object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||
not_null<Call*> call,
|
||||
Fn<void(std::vector<not_null<UserData*>>)> inviteUsers,
|
||||
Fn<void(std::vector<InviteRequest>)> inviteUsers,
|
||||
Fn<void()> shareLink) {
|
||||
const auto user = call->user();
|
||||
const auto weak = base::make_weak(call);
|
||||
|
@ -486,13 +685,7 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
|||
if (!call) {
|
||||
return;
|
||||
}
|
||||
auto peers = box->collectSelectedRows();
|
||||
auto users = ranges::views::all(
|
||||
peers
|
||||
) | ranges::views::transform([](not_null<PeerData*> peer) {
|
||||
return not_null(peer->asUser());
|
||||
}) | ranges::to_vector;
|
||||
inviteUsers(std::move(users));
|
||||
inviteUsers(raw->requests(box->collectSelectedRows()));
|
||||
});
|
||||
}
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
|
|
|
@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace Calls {
|
||||
class Call;
|
||||
class GroupCall;
|
||||
struct InviteRequest;
|
||||
} // namespace Calls
|
||||
|
||||
namespace Calls::Group {
|
||||
|
@ -83,7 +84,7 @@ private:
|
|||
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||
not_null<Call*> call,
|
||||
Fn<void(std::vector<not_null<UserData*>>)> inviteUsers,
|
||||
Fn<void(std::vector<InviteRequest>)> inviteUsers,
|
||||
Fn<void()> shareLink);
|
||||
|
||||
} // namespace Calls::Group
|
||||
|
|
|
@ -1006,8 +1006,8 @@ void Panel::migrationShowShareLink() {
|
|||
{ .st = DarkConferenceCallLinkStyle() });
|
||||
}
|
||||
|
||||
void Panel::migrationInviteUsers(std::vector<not_null<UserData*>> users) {
|
||||
const auto done = [=](GroupCall::InviteResult result) {
|
||||
void Panel::migrationInviteUsers(std::vector<InviteRequest> users) {
|
||||
const auto done = [=](InviteResult result) {
|
||||
showToast({ ComposeInviteResultToast(result) });
|
||||
};
|
||||
_call->inviteUsers(std::move(users), crl::guard(this, done));
|
||||
|
|
|
@ -73,6 +73,10 @@ struct CallSignalBars;
|
|||
struct CallBodyLayout;
|
||||
} // namespace style
|
||||
|
||||
namespace Calls {
|
||||
struct InviteRequest;
|
||||
} // namespace Calls
|
||||
|
||||
namespace Calls::Group {
|
||||
|
||||
class Toasts;
|
||||
|
@ -116,7 +120,7 @@ public:
|
|||
[[nodiscard]] bool isLayerShown() const;
|
||||
|
||||
void migrationShowShareLink();
|
||||
void migrationInviteUsers(std::vector<not_null<UserData*>> users);
|
||||
void migrationInviteUsers(std::vector<InviteRequest> users);
|
||||
|
||||
void minimize();
|
||||
void toggleFullScreen();
|
||||
|
|
|
@ -491,6 +491,7 @@ Call ComputeCallData(const MTPDmessageActionConferenceCall &call) {
|
|||
: call.is_active()
|
||||
? CallState::Active
|
||||
: CallState::Invitation),
|
||||
.video = call.is_video(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue