mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-03 21:54:05 +02:00
Initial call->confcall migration.
This commit is contained in:
parent
9dbd134601
commit
d052eac019
20 changed files with 561 additions and 182 deletions
|
@ -4655,6 +4655,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_call_error_camera_not_started" = "You can switch to video call once you're connected.";
|
||||
"lng_call_error_camera_outdated" = "{user}'s app does not support video calls. They need to update their app before you can call them.";
|
||||
"lng_call_error_audio_io" = "There seems to be a problem with your sound card. Please make sure that your computer's speakers and microphone are working and try again.";
|
||||
"lng_call_error_add_not_started" = "You can add more people once you're connected.";
|
||||
|
||||
"lng_call_bar_hangup" = "End call";
|
||||
"lng_call_leave_to_other_sure" = "End your active call and join this video chat?";
|
||||
|
@ -4691,6 +4692,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_call_start_video" = "Start Video";
|
||||
"lng_call_stop_video" = "Stop Video";
|
||||
"lng_call_screencast" = "Screencast";
|
||||
"lng_call_add_people" = "Add People";
|
||||
"lng_call_end_call" = "End Call";
|
||||
"lng_call_mute_audio" = "Mute";
|
||||
"lng_call_unmute_audio" = "Unmute";
|
||||
|
|
|
@ -24,7 +24,7 @@ CallSignalBars {
|
|||
inactiveOpacity: double;
|
||||
}
|
||||
|
||||
callWidthMin: 300px;
|
||||
callWidthMin: 372px;
|
||||
callHeightMin: 440px;
|
||||
callWidth: 720px;
|
||||
callHeight: 540px;
|
||||
|
@ -183,6 +183,18 @@ callCameraUnmute: CallButton(callMicrophoneUnmute) {
|
|||
}
|
||||
}
|
||||
}
|
||||
callAddPeople: CallButton(callAnswer) {
|
||||
button: IconButton(callButton) {
|
||||
icon: icon {{ "settings/group", callIconFgActive }};
|
||||
iconPosition: point(-1px, 24px);
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: callIconActiveRipple;
|
||||
}
|
||||
}
|
||||
bg: callIconBgActive;
|
||||
outerBg: callIconBgActive;
|
||||
label: callButtonLabel;
|
||||
}
|
||||
callCornerButtonInner: IconButton {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "calls/calls_panel.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "data/data_group_call.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
@ -527,20 +528,23 @@ crl::time Call::getDurationMs() const {
|
|||
return _startTime ? (crl::now() - _startTime) : 0;
|
||||
}
|
||||
|
||||
void Call::hangup() {
|
||||
void Call::hangup(Data::GroupCall *migrateCall, const QString &migrateSlug) {
|
||||
const auto state = _state.current();
|
||||
if (state == State::Busy) {
|
||||
if (state == State::Busy || state == State::MigrationHangingUp) {
|
||||
_delegate->callFinished(this);
|
||||
} else {
|
||||
const auto missed = (state == State::Ringing
|
||||
|| (state == State::Waiting && _type == Type::Outgoing));
|
||||
const auto declined = isIncomingWaiting();
|
||||
const auto reason = missed
|
||||
const auto reason = !migrateSlug.isEmpty()
|
||||
? MTP_phoneCallDiscardReasonMigrateConferenceCall(
|
||||
MTP_string(migrateSlug))
|
||||
: missed
|
||||
? MTP_phoneCallDiscardReasonMissed()
|
||||
: declined
|
||||
? MTP_phoneCallDiscardReasonBusy()
|
||||
: MTP_phoneCallDiscardReasonHangup();
|
||||
finish(FinishType::Ended, reason);
|
||||
finish(FinishType::Ended, reason, migrateCall);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -740,7 +744,10 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
|||
&& reason->type() == mtpc_phoneCallDiscardReasonDisconnect) {
|
||||
LOG(("Call Info: Discarded with DISCONNECT reason."));
|
||||
}
|
||||
if (reason && reason->type() == mtpc_phoneCallDiscardReasonBusy) {
|
||||
if (reason && reason->type() == mtpc_phoneCallDiscardReasonMigrateConferenceCall) {
|
||||
const auto slug = qs(reason->c_phoneCallDiscardReasonMigrateConferenceCall().vslug());
|
||||
finishByMigration(slug);
|
||||
} else if (reason && reason->type() == mtpc_phoneCallDiscardReasonBusy) {
|
||||
setState(State::Busy);
|
||||
} else if (_type == Type::Outgoing
|
||||
|| _state.current() == State::HangingUp) {
|
||||
|
@ -768,6 +775,32 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
|||
Unexpected("phoneCall type inside an existing call handleUpdate()");
|
||||
}
|
||||
|
||||
void Call::finishByMigration(const QString &slug) {
|
||||
if (_state.current() == State::MigrationHangingUp) {
|
||||
return;
|
||||
}
|
||||
setState(State::MigrationHangingUp);
|
||||
const auto limit = 5;
|
||||
const auto session = &_user->session();
|
||||
session->api().request(MTPphone_GetGroupCall(
|
||||
MTP_inputGroupCallSlug(MTP_string(slug)),
|
||||
MTP_int(limit)
|
||||
)).done([=](const MTPphone_GroupCall &result) {
|
||||
result.data().vcall().match([&](const auto &data) {
|
||||
const auto call = session->data().sharedConferenceCall(
|
||||
data.vid().v,
|
||||
data.vaccess_hash().v);
|
||||
call->processFullCall(result);
|
||||
Core::App().calls().startOrJoinConferenceCall({
|
||||
.call = call,
|
||||
.linkSlug = slug,
|
||||
});
|
||||
});
|
||||
}).fail(crl::guard(this, [=] {
|
||||
setState(State::Failed);
|
||||
})).send();
|
||||
}
|
||||
|
||||
void Call::updateRemoteMediaState(
|
||||
tgcalls::AudioState audio,
|
||||
tgcalls::VideoState video) {
|
||||
|
@ -1059,6 +1092,7 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
|||
const auto track = (state != State::FailedHangingUp)
|
||||
&& (state != State::Failed)
|
||||
&& (state != State::HangingUp)
|
||||
&& (state != State::MigrationHangingUp)
|
||||
&& (state != State::Ended)
|
||||
&& (state != State::EndedByOtherDevice)
|
||||
&& (state != State::Busy);
|
||||
|
@ -1175,6 +1209,11 @@ void Call::setState(State state) {
|
|||
&& state != State::Failed) {
|
||||
return;
|
||||
}
|
||||
if (was == State::MigrationHangingUp
|
||||
&& state != State::Ended
|
||||
&& state != State::Failed) {
|
||||
return;
|
||||
}
|
||||
if (was != state) {
|
||||
_state = state;
|
||||
|
||||
|
@ -1323,7 +1362,10 @@ rpl::producer<Webrtc::DeviceResolvedId> Call::cameraDeviceIdValue() const {
|
|||
return _cameraDeviceId.value();
|
||||
}
|
||||
|
||||
void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
|
||||
void Call::finish(
|
||||
FinishType type,
|
||||
const MTPPhoneCallDiscardReason &reason,
|
||||
Data::GroupCall *migrateCall) {
|
||||
Expects(type != FinishType::None);
|
||||
|
||||
setSignalBarCount(kSignalBarFinished);
|
||||
|
@ -1371,6 +1413,12 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
|
|||
|
||||
// We want to discard request still being sent and processed even if
|
||||
// the call is already destroyed.
|
||||
if (migrateCall) {
|
||||
_user->owner().registerInvitedToCallUser(
|
||||
migrateCall->id(),
|
||||
migrateCall,
|
||||
_user);
|
||||
}
|
||||
const auto session = &_user->session();
|
||||
const auto weak = base::make_weak(this);
|
||||
session->api().request(MTPphone_DiscardCall( // We send 'discard' here.
|
||||
|
|
|
@ -14,6 +14,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "mtproto/mtproto_auth_key.h"
|
||||
#include "webrtc/webrtc_device_resolver.h"
|
||||
|
||||
namespace Data {
|
||||
class GroupCall;
|
||||
} // namespace Data
|
||||
|
||||
namespace Media {
|
||||
namespace Audio {
|
||||
class Track;
|
||||
|
@ -122,6 +126,7 @@ public:
|
|||
FailedHangingUp,
|
||||
Failed,
|
||||
HangingUp,
|
||||
MigrationHangingUp,
|
||||
Ended,
|
||||
EndedByOtherDevice,
|
||||
ExchangingKeys,
|
||||
|
@ -198,7 +203,9 @@ public:
|
|||
|
||||
void applyUserConfirmation();
|
||||
void answer();
|
||||
void hangup();
|
||||
void hangup(
|
||||
Data::GroupCall *migrateCall = nullptr,
|
||||
const QString &migrateSlug = QString());
|
||||
void redial();
|
||||
|
||||
bool isKeyShaForFingerprintReady() const;
|
||||
|
@ -246,7 +253,9 @@ private:
|
|||
void finish(
|
||||
FinishType type,
|
||||
const MTPPhoneCallDiscardReason &reason
|
||||
= MTP_phoneCallDiscardReasonDisconnect());
|
||||
= MTP_phoneCallDiscardReasonDisconnect(),
|
||||
Data::GroupCall *migrateCall = nullptr);
|
||||
void finishByMigration(const QString &slug);
|
||||
void startOutgoing();
|
||||
void startIncoming();
|
||||
void startWaitingTrack();
|
||||
|
|
|
@ -230,12 +230,13 @@ void Instance::startOrJoinGroupCall(
|
|||
});
|
||||
}
|
||||
|
||||
void Instance::startOrJoinConferenceCall(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
StartConferenceCallArgs args) {
|
||||
destroyCurrentCall();
|
||||
void Instance::startOrJoinConferenceCall(StartConferenceCallArgs args) {
|
||||
destroyCurrentCall(
|
||||
args.migrating ? args.call.get() : nullptr,
|
||||
args.migrating ? args.linkSlug : QString());
|
||||
|
||||
const auto session = &args.call->peer()->session();
|
||||
const auto showShareLink = args.migrating && args.invite.empty();
|
||||
auto call = std::make_unique<GroupCall>(
|
||||
_delegate.get(),
|
||||
Calls::Group::ConferenceInfo{
|
||||
|
@ -254,6 +255,11 @@ void Instance::startOrJoinConferenceCall(
|
|||
_currentGroupCallPanel = std::make_unique<Group::Panel>(raw);
|
||||
_currentGroupCall = std::move(call);
|
||||
_currentGroupCallChanges.fire_copy(raw);
|
||||
if (!args.invite.empty()) {
|
||||
_currentGroupCallPanel->migrationInviteUsers(std::move(args.invite));
|
||||
} else if (args.migrating) {
|
||||
_currentGroupCallPanel->migrationShowShareLink();
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::confirmLeaveCurrent(
|
||||
|
@ -435,24 +441,6 @@ void Instance::createGroupCall(
|
|||
_currentGroupCallChanges.fire_copy(raw);
|
||||
}
|
||||
|
||||
void Instance::createConferenceCall(Group::ConferenceInfo info) {
|
||||
destroyCurrentCall();
|
||||
|
||||
auto call = std::make_unique<GroupCall>(
|
||||
_delegate.get(),
|
||||
std::move(info));
|
||||
const auto raw = call.get();
|
||||
|
||||
raw->peer()->session().account().sessionChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
destroyGroupCall(raw);
|
||||
}, raw->lifetime());
|
||||
|
||||
_currentGroupCallPanel = std::make_unique<Group::Panel>(raw);
|
||||
_currentGroupCall = std::move(call);
|
||||
_currentGroupCallChanges.fire_copy(raw);
|
||||
}
|
||||
|
||||
void Instance::refreshDhConfig() {
|
||||
Expects(_currentCall != nullptr);
|
||||
|
||||
|
@ -744,9 +732,11 @@ bool Instance::inGroupCall() const {
|
|||
&& (state != GroupCall::State::Failed);
|
||||
}
|
||||
|
||||
void Instance::destroyCurrentCall() {
|
||||
void Instance::destroyCurrentCall(
|
||||
Data::GroupCall *migrateCall,
|
||||
const QString &migrateSlug) {
|
||||
if (const auto current = currentCall()) {
|
||||
current->hangup();
|
||||
current->hangup(migrateCall, migrateSlug);
|
||||
if (const auto still = currentCall()) {
|
||||
destroyCall(still);
|
||||
}
|
||||
|
|
|
@ -73,6 +73,8 @@ struct StartConferenceCallArgs {
|
|||
std::shared_ptr<TdE2E::Call> e2e;
|
||||
QString linkSlug;
|
||||
MsgId joinMessageId;
|
||||
std::vector<not_null<UserData*>> invite;
|
||||
bool migrating = false;
|
||||
};
|
||||
|
||||
class Instance final : public base::has_weak_ptr {
|
||||
|
@ -85,9 +87,7 @@ public:
|
|||
std::shared_ptr<Ui::Show> show,
|
||||
not_null<PeerData*> peer,
|
||||
StartGroupCallArgs args);
|
||||
void startOrJoinConferenceCall(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
StartConferenceCallArgs args);
|
||||
void startOrJoinConferenceCall(StartConferenceCallArgs args);
|
||||
void showStartWithRtmp(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
not_null<PeerData*> peer);
|
||||
|
@ -140,7 +140,6 @@ private:
|
|||
void createGroupCall(
|
||||
Group::JoinInfo info,
|
||||
const MTPInputGroupCall &inputCall);
|
||||
void createConferenceCall(Group::ConferenceInfo info);
|
||||
void destroyGroupCall(not_null<GroupCall*> call);
|
||||
void confirmLeaveCurrent(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
|
@ -156,7 +155,9 @@ private:
|
|||
void refreshServerConfig(not_null<Main::Session*> session);
|
||||
bytes::const_span updateDhConfig(const MTPmessages_DhConfig &data);
|
||||
|
||||
void destroyCurrentCall();
|
||||
void destroyCurrentCall(
|
||||
Data::GroupCall *migrateCall = nullptr,
|
||||
const QString &migrateSlug = QString());
|
||||
void handleCallUpdate(
|
||||
not_null<Main::Session*> session,
|
||||
const MTPPhoneCall &call);
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_cloud_file.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "calls/group/calls_group_common.h"
|
||||
#include "calls/group/calls_group_invite_controller.h"
|
||||
#include "calls/ui/calls_device_menu.h"
|
||||
#include "calls/calls_emoji_fingerprint.h"
|
||||
#include "calls/calls_signal_bars.h"
|
||||
|
@ -45,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/integration.h"
|
||||
#include "core/application.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/session/session_show.h"
|
||||
#include "main/main_session.h"
|
||||
#include "apiwrap.h"
|
||||
#include "platform/platform_specific.h"
|
||||
|
@ -92,6 +94,77 @@ constexpr auto kHideControlsQuickTimeout = 2 * crl::time(1000);
|
|||
</svg>)";
|
||||
}
|
||||
|
||||
class Show final : public Main::SessionShow {
|
||||
public:
|
||||
explicit Show(not_null<Panel*> panel);
|
||||
~Show();
|
||||
|
||||
void showOrHideBoxOrLayer(
|
||||
std::variant<
|
||||
v::null_t,
|
||||
object_ptr<Ui::BoxContent>,
|
||||
std::unique_ptr<Ui::LayerWidget>> &&layer,
|
||||
Ui::LayerOptions options,
|
||||
anim::type animated) const override;
|
||||
[[nodiscard]] not_null<QWidget*> toastParent() const override;
|
||||
[[nodiscard]] bool valid() const override;
|
||||
operator bool() const override;
|
||||
|
||||
[[nodiscard]] Main::Session &session() const override;
|
||||
|
||||
private:
|
||||
const base::weak_ptr<Panel> _panel;
|
||||
|
||||
};
|
||||
|
||||
Show::Show(not_null<Panel*> panel)
|
||||
: _panel(base::make_weak(panel)) {
|
||||
}
|
||||
|
||||
Show::~Show() = default;
|
||||
|
||||
void Show::showOrHideBoxOrLayer(
|
||||
std::variant<
|
||||
v::null_t,
|
||||
object_ptr<Ui::BoxContent>,
|
||||
std::unique_ptr<Ui::LayerWidget>> &&layer,
|
||||
Ui::LayerOptions options,
|
||||
anim::type animated) const {
|
||||
using UniqueLayer = std::unique_ptr<Ui::LayerWidget>;
|
||||
using ObjectBox = object_ptr<Ui::BoxContent>;
|
||||
if (auto layerWidget = std::get_if<UniqueLayer>(&layer)) {
|
||||
if (const auto panel = _panel.get()) {
|
||||
panel->showLayer(std::move(*layerWidget), options, animated);
|
||||
}
|
||||
} else if (auto box = std::get_if<ObjectBox>(&layer)) {
|
||||
if (const auto panel = _panel.get()) {
|
||||
panel->showBox(std::move(*box), options, animated);
|
||||
}
|
||||
} else if (const auto panel = _panel.get()) {
|
||||
panel->hideLayer(animated);
|
||||
}
|
||||
}
|
||||
|
||||
not_null<QWidget*> Show::toastParent() const {
|
||||
const auto panel = _panel.get();
|
||||
Assert(panel != nullptr);
|
||||
return panel->widget();
|
||||
}
|
||||
|
||||
bool Show::valid() const {
|
||||
return !_panel.empty();
|
||||
}
|
||||
|
||||
Show::operator bool() const {
|
||||
return valid();
|
||||
}
|
||||
|
||||
Main::Session &Show::session() const {
|
||||
const auto panel = _panel.get();
|
||||
Assert(panel != nullptr);
|
||||
return panel->user()->session();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Panel::Panel(not_null<Call*> call)
|
||||
|
@ -121,6 +194,9 @@ Panel::Panel(not_null<Call*> call)
|
|||
widget(),
|
||||
st::callMicrophoneMute,
|
||||
&st::callMicrophoneUnmute))
|
||||
, _addPeople(
|
||||
widget(),
|
||||
object_ptr<Ui::CallButton>(widget(), st::callAddPeople))
|
||||
, _name(widget(), st::callName)
|
||||
, _status(widget(), st::callStatus)
|
||||
, _hideControlsTimer([=] { requestControlsHidden(true); })
|
||||
|
@ -133,6 +209,8 @@ Panel::Panel(not_null<Call*> call)
|
|||
_cancel->setDuration(st::callPanelDuration);
|
||||
_cancel->entity()->setText(tr::lng_call_cancel());
|
||||
_screencast->setDuration(st::callPanelDuration);
|
||||
_addPeople->setDuration(st::callPanelDuration);
|
||||
_addPeople->entity()->setText(tr::lng_call_add_people());
|
||||
|
||||
initWindow();
|
||||
initWidget();
|
||||
|
@ -153,6 +231,62 @@ bool Panel::isActive() const {
|
|||
return window()->isActiveWindow() && isVisible();
|
||||
}
|
||||
|
||||
base::weak_ptr<Ui::Toast::Instance> Panel::showToast(
|
||||
const QString &text,
|
||||
crl::time duration) {
|
||||
return showToast({
|
||||
.text = { text },
|
||||
.duration = duration,
|
||||
});
|
||||
}
|
||||
|
||||
base::weak_ptr<Ui::Toast::Instance> Panel::showToast(
|
||||
TextWithEntities &&text,
|
||||
crl::time duration) {
|
||||
return showToast({
|
||||
.text = std::move(text),
|
||||
.duration = duration,
|
||||
});
|
||||
}
|
||||
|
||||
base::weak_ptr<Ui::Toast::Instance> Panel::showToast(
|
||||
Ui::Toast::Config &&config) {
|
||||
if (!config.st) {
|
||||
config.st = &st::callErrorToast;
|
||||
}
|
||||
return Show(this).showToast(std::move(config));
|
||||
}
|
||||
|
||||
void Panel::showBox(object_ptr<Ui::BoxContent> box) {
|
||||
showBox(std::move(box), Ui::LayerOption::KeepOther, anim::type::normal);
|
||||
}
|
||||
|
||||
void Panel::showBox(
|
||||
object_ptr<Ui::BoxContent> box,
|
||||
Ui::LayerOptions options,
|
||||
anim::type animated) {
|
||||
_layerBg->showBox(std::move(box), options, animated);
|
||||
}
|
||||
|
||||
void Panel::showLayer(
|
||||
std::unique_ptr<Ui::LayerWidget> layer,
|
||||
Ui::LayerOptions options,
|
||||
anim::type animated) {
|
||||
_layerBg->showLayer(std::move(layer), options, animated);
|
||||
}
|
||||
|
||||
void Panel::hideLayer(anim::type animated) {
|
||||
_layerBg->hideAll(animated);
|
||||
}
|
||||
|
||||
bool Panel::isLayerShown() const {
|
||||
return _layerBg->topShownLayer() != nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Main::SessionShow> Panel::uiShow() {
|
||||
return std::make_shared<Show>(this);
|
||||
}
|
||||
|
||||
void Panel::showAndActivate() {
|
||||
if (window()->isHidden()) {
|
||||
window()->show();
|
||||
|
@ -303,7 +437,7 @@ void Panel::initControls() {
|
|||
return;
|
||||
} else if (!env->desktopCaptureAllowed()) {
|
||||
if (auto box = Group::ScreenSharingPrivacyRequestBox()) {
|
||||
_layerBg->showBox(std::move(box));
|
||||
showBox(std::move(box));
|
||||
}
|
||||
} else if (const auto source = env->uniqueDesktopCaptureSource()) {
|
||||
if (!chooseSourceActiveDeviceId().isEmpty()) {
|
||||
|
@ -318,9 +452,42 @@ void Panel::initControls() {
|
|||
_camera->setClickedCallback([=] {
|
||||
if (!_call) {
|
||||
return;
|
||||
} else {
|
||||
_call->toggleCameraSharing(!_call->isSharingCamera());
|
||||
}
|
||||
_call->toggleCameraSharing(!_call->isSharingCamera());
|
||||
});
|
||||
_addPeople->entity()->setClickedCallback([=] {
|
||||
if (!_call || _call->state() != Call::State::Established) {
|
||||
showToast(tr::lng_call_error_add_not_started(tr::now));
|
||||
return;
|
||||
}
|
||||
const auto call = _call;
|
||||
const auto creating = std::make_shared<bool>();
|
||||
const auto finish = [=](QString link) {
|
||||
if (link.isEmpty()) {
|
||||
*creating = false;
|
||||
}
|
||||
};
|
||||
const auto create = [=](std::vector<not_null<UserData*>> users) {
|
||||
if (*creating) {
|
||||
return;
|
||||
}
|
||||
*creating = true;
|
||||
Group::MakeConferenceCall({
|
||||
.show = uiShow(),
|
||||
.finished = finish,
|
||||
.invite = std::move(users),
|
||||
.joining = true,
|
||||
.migrating = true,
|
||||
});
|
||||
};
|
||||
const auto invite = crl::guard(call, [=](
|
||||
std::vector<not_null<UserData*>> users) {
|
||||
create(std::move(users));
|
||||
});
|
||||
const auto share = crl::guard(call, [=] {
|
||||
create({});
|
||||
});
|
||||
showBox(Group::PrepareInviteBox(call, invite, share));
|
||||
});
|
||||
|
||||
_updateDurationTimer.setCallback([this] {
|
||||
|
@ -605,6 +772,7 @@ void Panel::reinitWithCall(Call *call) {
|
|||
&& state != State::EndedByOtherDevice
|
||||
&& state != State::Failed
|
||||
&& state != State::FailedHangingUp
|
||||
&& state != State::MigrationHangingUp
|
||||
&& state != State::HangingUp) {
|
||||
refreshOutgoingPreviewInBody(state);
|
||||
}
|
||||
|
@ -630,10 +798,7 @@ void Panel::reinitWithCall(Call *call) {
|
|||
}
|
||||
Unexpected("Error type in _call->errors().");
|
||||
}();
|
||||
Ui::Toast::Show(widget(), Ui::Toast::Config{
|
||||
.text = { text },
|
||||
.st = &st::callErrorToast,
|
||||
});
|
||||
showToast(text);
|
||||
}, _callLifetime);
|
||||
|
||||
_name->setText(_user->name());
|
||||
|
@ -647,6 +812,7 @@ void Panel::reinitWithCall(Call *call) {
|
|||
_startVideo->raise();
|
||||
}
|
||||
_mute->raise();
|
||||
_addPeople->raise();
|
||||
|
||||
_powerSaveBlocker = std::make_unique<base::PowerSaveBlocker>(
|
||||
base::PowerSaveBlockType::PreventDisplaySleep,
|
||||
|
@ -1077,11 +1243,7 @@ void Panel::updateHangupGeometry() {
|
|||
// Screencast - Camera - Cancel/Decline - Answer/Hangup/Redial - Mute.
|
||||
const auto buttonWidth = st::callCancel.button.width;
|
||||
const auto cancelWidth = buttonWidth * (1. - hangupProgress);
|
||||
const auto cancelLeft = (isWaitingUser)
|
||||
? ((widget()->width() - buttonWidth) / 2)
|
||||
: (_mute->animating())
|
||||
? ((widget()->width() - cancelWidth) / 2)
|
||||
: ((widget()->width() / 2) - cancelWidth);
|
||||
const auto cancelLeft = (widget()->width() - buttonWidth) / 2;
|
||||
|
||||
_cancel->moveToLeft(cancelLeft, _buttonsTop);
|
||||
_decline->moveToLeft(cancelLeft, _buttonsTop);
|
||||
|
@ -1089,6 +1251,7 @@ void Panel::updateHangupGeometry() {
|
|||
_screencast->moveToLeft(_camera->x() - buttonWidth, _buttonsTop);
|
||||
_answerHangupRedial->moveToLeft(cancelLeft + cancelWidth, _buttonsTop);
|
||||
_mute->moveToLeft(_answerHangupRedial->x() + buttonWidth, _buttonsTop);
|
||||
_addPeople->moveToLeft(_mute->x() + buttonWidth, _buttonsTop);
|
||||
if (_startVideo) {
|
||||
_startVideo->moveToLeft(_camera->x(), _camera->y());
|
||||
}
|
||||
|
@ -1136,12 +1299,17 @@ not_null<Ui::RpWidget*> Panel::widget() const {
|
|||
return _window.widget();
|
||||
}
|
||||
|
||||
not_null<UserData*> Panel::user() const {
|
||||
return _user;
|
||||
}
|
||||
|
||||
void Panel::stateChanged(State state) {
|
||||
Expects(_call != nullptr);
|
||||
|
||||
updateStatusText(state);
|
||||
|
||||
if ((state != State::HangingUp)
|
||||
&& (state != State::MigrationHangingUp)
|
||||
&& (state != State::Ended)
|
||||
&& (state != State::EndedByOtherDevice)
|
||||
&& (state != State::FailedHangingUp)
|
||||
|
@ -1182,6 +1350,7 @@ void Panel::stateChanged(State state) {
|
|||
toggleButton(
|
||||
_screencast,
|
||||
!(isBusy || isWaitingUser || incomingWaiting));
|
||||
toggleButton(_addPeople, !isWaitingUser);
|
||||
const auto hangupShown = !_decline->toggled()
|
||||
&& !_cancel->toggled();
|
||||
if (_hangupShown != hangupShown) {
|
||||
|
@ -1232,7 +1401,8 @@ void Panel::updateStatusText(State state) {
|
|||
switch (state) {
|
||||
case State::Starting:
|
||||
case State::WaitingInit:
|
||||
case State::WaitingInitAck: return tr::lng_call_status_connecting(tr::now);
|
||||
case State::WaitingInitAck:
|
||||
case State::MigrationHangingUp: return tr::lng_call_status_connecting(tr::now);
|
||||
case State::Established: {
|
||||
if (_call) {
|
||||
auto durationMs = _call->getDurationMs();
|
||||
|
|
|
@ -27,7 +27,15 @@ namespace Data {
|
|||
class PhotoMedia;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
class SessionShow;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class BoxContent;
|
||||
class LayerWidget;
|
||||
enum class LayerOption;
|
||||
using LayerOptions = base::flags<LayerOption>;
|
||||
class IconButton;
|
||||
class CallButton;
|
||||
class LayerManager;
|
||||
|
@ -38,14 +46,17 @@ template <typename Widget>
|
|||
class PaddingWrap;
|
||||
class RpWindow;
|
||||
class PopupMenu;
|
||||
namespace GL {
|
||||
enum class Backend;
|
||||
} // namespace GL
|
||||
namespace Platform {
|
||||
struct SeparateTitleControls;
|
||||
} // namespace Platform
|
||||
} // namespace Ui
|
||||
|
||||
namespace Ui::Toast {
|
||||
class Instance;
|
||||
struct Config;
|
||||
} // namespace Ui::Toast
|
||||
|
||||
namespace Ui::Platform {
|
||||
struct SeparateTitleControls;
|
||||
} // namespace Ui::Platform
|
||||
|
||||
namespace style {
|
||||
struct CallSignalBars;
|
||||
struct CallBodyLayout;
|
||||
|
@ -58,13 +69,39 @@ class SignalBars;
|
|||
class VideoBubble;
|
||||
struct DeviceSelection;
|
||||
|
||||
class Panel final : private Group::Ui::DesktopCapture::ChooseSourceDelegate {
|
||||
class Panel final
|
||||
: public base::has_weak_ptr
|
||||
, private Group::Ui::DesktopCapture::ChooseSourceDelegate {
|
||||
public:
|
||||
Panel(not_null<Call*> call);
|
||||
~Panel();
|
||||
|
||||
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
|
||||
[[nodiscard]] not_null<UserData*> user() const;
|
||||
[[nodiscard]] bool isVisible() const;
|
||||
[[nodiscard]] bool isActive() const;
|
||||
|
||||
base::weak_ptr<Ui::Toast::Instance> showToast(
|
||||
const QString &text,
|
||||
crl::time duration = 0);
|
||||
base::weak_ptr<Ui::Toast::Instance> showToast(
|
||||
TextWithEntities &&text,
|
||||
crl::time duration = 0);
|
||||
base::weak_ptr<Ui::Toast::Instance> showToast(
|
||||
Ui::Toast::Config &&config);
|
||||
|
||||
void showBox(object_ptr<Ui::BoxContent> box);
|
||||
void showBox(
|
||||
object_ptr<Ui::BoxContent> box,
|
||||
Ui::LayerOptions options,
|
||||
anim::type animated = anim::type::normal);
|
||||
void showLayer(
|
||||
std::unique_ptr<Ui::LayerWidget> layer,
|
||||
Ui::LayerOptions options,
|
||||
anim::type animated = anim::type::normal);
|
||||
void hideLayer(anim::type animated = anim::type::normal);
|
||||
[[nodiscard]] bool isLayerShown() const;
|
||||
|
||||
void showAndActivate();
|
||||
void minimize();
|
||||
void toggleFullScreen();
|
||||
|
@ -83,6 +120,8 @@ public:
|
|||
|
||||
[[nodiscard]] rpl::producer<bool> startOutgoingRequests() const;
|
||||
|
||||
[[nodiscard]] std::shared_ptr<Main::SessionShow> uiShow();
|
||||
|
||||
[[nodiscard]] rpl::lifetime &lifetime();
|
||||
|
||||
private:
|
||||
|
@ -97,7 +136,6 @@ private:
|
|||
};
|
||||
|
||||
[[nodiscard]] not_null<Ui::RpWindow*> window() const;
|
||||
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
|
||||
|
||||
void paint(QRect clip);
|
||||
|
||||
|
@ -170,6 +208,7 @@ private:
|
|||
base::unique_qptr<Ui::CallButton> _startVideo;
|
||||
object_ptr<Ui::FadeWrap<Ui::CallButton>> _mute;
|
||||
Ui::CallButton *_audioDeviceToggle = nullptr;
|
||||
object_ptr < Ui::FadeWrap<Ui::CallButton>> _addPeople;
|
||||
object_ptr<Ui::FlatLabel> _name;
|
||||
object_ptr<Ui::FlatLabel> _status;
|
||||
object_ptr<Ui::RpWidget> _fingerprint = { nullptr };
|
||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "lang/lang_hardcoded.h"
|
||||
#include "boxes/peers/edit_participants_box.h" // SubscribeToMigration.
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "base/unixtime.h"
|
||||
|
@ -1164,6 +1165,15 @@ std::shared_ptr<Data::GroupCall> GroupCall::conferenceCall() const {
|
|||
return _conferenceCall;
|
||||
}
|
||||
|
||||
QString GroupCall::existingConferenceLink() const {
|
||||
Expects(!_conferenceLinkSlug.isEmpty());
|
||||
|
||||
const auto session = &_peer->session();
|
||||
return !_conferenceLinkSlug.isEmpty()
|
||||
? session->createInternalLinkFull("call/" + _conferenceLinkSlug)
|
||||
: QString();
|
||||
}
|
||||
|
||||
rpl::producer<not_null<Data::GroupCall*>> GroupCall::real() const {
|
||||
if (const auto real = lookupReal()) {
|
||||
return rpl::single(not_null{ real });
|
||||
|
@ -3902,4 +3912,41 @@ void GroupCall::destroyScreencast() {
|
|||
}
|
||||
}
|
||||
|
||||
TextWithEntities ComposeInviteResultToast(
|
||||
const GroupCall::InviteResult &result) {
|
||||
auto text = TextWithEntities();
|
||||
const auto invited = int(result.invited.size());
|
||||
const auto restricted = int(result.privacyRestricted.size());
|
||||
if (invited == 1) {
|
||||
text.append(tr::lng_confcall_invite_done_user(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Bold(result.invited.front()->shortName()),
|
||||
Ui::Text::RichLangValue));
|
||||
} else if (invited > 1) {
|
||||
text.append(tr::lng_confcall_invite_done_many(
|
||||
tr::now,
|
||||
lt_count,
|
||||
invited,
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
if (invited && restricted) {
|
||||
text.append(u"\n\n"_q);
|
||||
}
|
||||
if (restricted == 1) {
|
||||
text.append(tr::lng_confcall_invite_fail_user(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Bold(result.privacyRestricted.front()->shortName()),
|
||||
Ui::Text::RichLangValue));
|
||||
} else if (restricted > 1) {
|
||||
text.append(tr::lng_confcall_invite_fail_many(
|
||||
tr::now,
|
||||
lt_count,
|
||||
restricted,
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
} // namespace Calls
|
||||
|
|
|
@ -257,6 +257,7 @@ public:
|
|||
|
||||
[[nodiscard]] Data::GroupCall *lookupReal() const;
|
||||
[[nodiscard]] std::shared_ptr<Data::GroupCall> conferenceCall() const;
|
||||
[[nodiscard]] QString existingConferenceLink() const;
|
||||
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
|
||||
[[nodiscard]] rpl::producer<QByteArray> emojiHashValue() const;
|
||||
|
||||
|
@ -752,4 +753,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
[[nodiscard]] TextWithEntities ComposeInviteResultToast(
|
||||
const GroupCall::InviteResult &result);
|
||||
|
||||
} // namespace Calls
|
||||
|
|
|
@ -9,9 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "apiwrap.h"
|
||||
#include "base/platform/base_platform_info.h"
|
||||
#include "base/random.h"
|
||||
#include "boxes/share_box.h"
|
||||
#include "calls/calls_instance.h"
|
||||
#include "core/application.h"
|
||||
#include "core/local_url_handlers.h"
|
||||
#include "data/data_group_call.h"
|
||||
#include "data/data_session.h"
|
||||
#include "info/bot/starref/info_bot_starref_common.h"
|
||||
#include "ui/boxes/boost_box.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
|
@ -31,6 +35,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include <QtGui/QClipboard>
|
||||
|
||||
namespace Calls::Group {
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] QString ExtractConferenceSlug(const QString &link) {
|
||||
const auto local = Core::TryConvertUrlToLocal(link);
|
||||
const auto parts1 = QStringView(local).split('#');
|
||||
if (!parts1.isEmpty()) {
|
||||
const auto parts2 = parts1.front().split('&');
|
||||
if (!parts2.isEmpty()) {
|
||||
const auto parts3 = parts2.front().split(u"slug="_q);
|
||||
if (parts3.size() > 1) {
|
||||
return parts3.back().toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
object_ptr<Ui::GenericBox> ScreenSharingPrivacyRequestBox() {
|
||||
#ifdef Q_OS_MAC
|
||||
|
@ -107,7 +129,6 @@ void ShowConferenceCallLinkBox(
|
|||
ConferenceCallLinkArgs &&args) {
|
||||
const auto st = args.st;
|
||||
const auto initial = args.initial;
|
||||
const auto weakWindow = args.weakWindow;
|
||||
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
box->setStyle(st.box
|
||||
? *st.box
|
||||
|
@ -151,7 +172,7 @@ void ShowConferenceCallLinkBox(
|
|||
|
||||
const auto copyCallback = [=] {
|
||||
QApplication::clipboard()->setText(link);
|
||||
box->uiShow()->showToast(tr::lng_username_copied(tr::now));
|
||||
show->showToast(tr::lng_username_copied(tr::now));
|
||||
};
|
||||
const auto shareCallback = [=] {
|
||||
FastShareLink(
|
||||
|
@ -218,12 +239,11 @@ void ShowConferenceCallLinkBox(
|
|||
: st::confcallLinkCenteredText));
|
||||
footer->setTryMakeSimilarLines(true);
|
||||
footer->setClickHandlerFilter([=](const auto &...) {
|
||||
const auto local = Core::TryConvertUrlToLocal(link);
|
||||
if (const auto controller = weakWindow.get()) {
|
||||
controller->resolveConferenceCall(
|
||||
local,
|
||||
crl::guard(box, [=](bool ok) { if (ok) box->closeBox(); }),
|
||||
true);
|
||||
if (auto slug = ExtractConferenceSlug(link); !slug.isEmpty()) {
|
||||
Core::App().calls().startOrJoinConferenceCall({
|
||||
.call = call,
|
||||
.linkSlug = std::move(slug),
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -251,6 +271,7 @@ void ExportConferenceCallLink(
|
|||
std::shared_ptr<Data::GroupCall> call,
|
||||
ConferenceCallLinkArgs &&args) {
|
||||
const auto session = &show->session();
|
||||
const auto invite = std::move(args.invite);
|
||||
const auto finished = std::move(args.finished);
|
||||
|
||||
using Flag = MTPphone_ExportGroupCallInvite::Flag;
|
||||
|
@ -259,18 +280,63 @@ void ExportConferenceCallLink(
|
|||
call->input()
|
||||
)).done([=](const MTPphone_ExportedGroupCallInvite &result) {
|
||||
const auto link = qs(result.data().vlink());
|
||||
if (args.joining) {
|
||||
if (auto slug = ExtractConferenceSlug(link); !slug.isEmpty()) {
|
||||
Core::App().calls().startOrJoinConferenceCall({
|
||||
.call = call,
|
||||
.linkSlug = std::move(slug),
|
||||
.invite = invite,
|
||||
.migrating = args.migrating,
|
||||
});
|
||||
}
|
||||
if (const auto onstack = finished) {
|
||||
finished(QString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
Calls::Group::ShowConferenceCallLinkBox(
|
||||
show,
|
||||
call,
|
||||
link,
|
||||
base::duplicate(args));
|
||||
if (const auto onstack = finished) {
|
||||
finished(true);
|
||||
finished(link);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
show->showToast(error.type());
|
||||
if (const auto onstack = finished) {
|
||||
finished(false);
|
||||
finished(QString());
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
||||
void MakeConferenceCall(ConferenceFactoryArgs &&args) {
|
||||
const auto show = std::move(args.show);
|
||||
const auto finished = std::move(args.finished);
|
||||
const auto joining = args.joining;
|
||||
const auto migrating = args.migrating;
|
||||
const auto invite = std::move(args.invite);
|
||||
const auto session = &show->session();
|
||||
session->api().request(MTPphone_CreateConferenceCall(
|
||||
MTP_int(base::RandomValue<int32>())
|
||||
)).done([=](const MTPphone_GroupCall &result) {
|
||||
result.data().vcall().match([&](const auto &data) {
|
||||
const auto call = session->data().sharedConferenceCall(
|
||||
data.vid().v,
|
||||
data.vaccess_hash().v);
|
||||
call->processFullCall(result);
|
||||
Calls::Group::ExportConferenceCallLink(show, call, {
|
||||
.initial = true,
|
||||
.joining = joining,
|
||||
.migrating = migrating,
|
||||
.finished = finished,
|
||||
.invite = invite,
|
||||
});
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
show->showToast(error.type());
|
||||
if (const auto onstack = finished) {
|
||||
onstack(QString());
|
||||
}
|
||||
}).send();
|
||||
}
|
||||
|
|
|
@ -142,8 +142,10 @@ struct ConferenceCallLinkStyleOverrides {
|
|||
|
||||
struct ConferenceCallLinkArgs {
|
||||
bool initial = false;
|
||||
Fn<void(bool)> finished;
|
||||
base::weak_ptr<Window::SessionController> weakWindow = nullptr;
|
||||
bool joining = false;
|
||||
bool migrating = false;
|
||||
Fn<void(QString)> finished;
|
||||
std::vector<not_null<UserData*>> invite;
|
||||
ConferenceCallLinkStyleOverrides st;
|
||||
};
|
||||
void ShowConferenceCallLinkBox(
|
||||
|
@ -157,4 +159,13 @@ void ExportConferenceCallLink(
|
|||
std::shared_ptr<Data::GroupCall> call,
|
||||
ConferenceCallLinkArgs &&args);
|
||||
|
||||
struct ConferenceFactoryArgs {
|
||||
std::shared_ptr<Main::SessionShow> show;
|
||||
Fn<void(QString)> finished;
|
||||
std::vector<not_null<UserData*>> invite;
|
||||
bool joining = false;
|
||||
bool migrating = false;
|
||||
};
|
||||
void MakeConferenceCall(ConferenceFactoryArgs &&args);
|
||||
|
||||
} // namespace Calls::Group
|
||||
|
|
|
@ -10,6 +10,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_menu.h"
|
||||
#include "calls/calls_call.h"
|
||||
#include "boxes/peer_lists_box.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_channel.h"
|
||||
|
@ -80,7 +81,7 @@ protected:
|
|||
private:
|
||||
[[nodiscard]] int fullCount() const;
|
||||
|
||||
base::flat_set<not_null<UserData*>> _alreadyIn;
|
||||
const base::flat_set<not_null<UserData*>> _alreadyIn;
|
||||
const Fn<void()> _shareLink;
|
||||
rpl::variable<bool> _hasSelected;
|
||||
|
||||
|
@ -93,7 +94,6 @@ ConfInviteController::ConfInviteController(
|
|||
: ContactsBoxController(session)
|
||||
, _alreadyIn(std::move(alreadyIn))
|
||||
, _shareLink(std::move(shareLink)) {
|
||||
_alreadyIn.remove(session->user());
|
||||
}
|
||||
|
||||
rpl::producer<bool> ConfInviteController::hasSelectedValue() const {
|
||||
|
@ -161,43 +161,6 @@ void ConfInviteController::prepareViewHook() {
|
|||
delegate()->peerListSetAboveWidget(std::move(button));
|
||||
}
|
||||
|
||||
[[nodiscard]] TextWithEntities ComposeInviteResultToast(
|
||||
const GroupCall::InviteResult &result) {
|
||||
auto text = TextWithEntities();
|
||||
const auto invited = int(result.invited.size());
|
||||
const auto restricted = int(result.privacyRestricted.size());
|
||||
if (invited == 1) {
|
||||
text.append(tr::lng_confcall_invite_done_user(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Bold(result.invited.front()->shortName()),
|
||||
Ui::Text::RichLangValue));
|
||||
} else if (invited > 1) {
|
||||
text.append(tr::lng_confcall_invite_done_many(
|
||||
tr::now,
|
||||
lt_count,
|
||||
invited,
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
if (invited && restricted) {
|
||||
text.append(u"\n\n"_q);
|
||||
}
|
||||
if (restricted == 1) {
|
||||
text.append(tr::lng_confcall_invite_fail_user(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Bold(result.privacyRestricted.front()->shortName()),
|
||||
Ui::Text::RichLangValue));
|
||||
} else if (restricted > 1) {
|
||||
text.append(tr::lng_confcall_invite_fail_many(
|
||||
tr::now,
|
||||
lt_count,
|
||||
restricted,
|
||||
Ui::Text::RichLangValue));
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
InviteController::InviteController(
|
||||
|
@ -494,4 +457,44 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
|||
return Box<PeerListsBox>(std::move(controllers), initBox);
|
||||
}
|
||||
|
||||
object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||
not_null<Call*> call,
|
||||
Fn<void(std::vector<not_null<UserData*>>)> inviteUsers,
|
||||
Fn<void()> shareLink) {
|
||||
const auto user = call->user();
|
||||
const auto weak = base::make_weak(call);
|
||||
auto alreadyIn = base::flat_set<not_null<UserData*>>{ user };
|
||||
auto controller = std::make_unique<ConfInviteController>(
|
||||
&user->session(),
|
||||
alreadyIn,
|
||||
shareLink);
|
||||
const auto raw = controller.get();
|
||||
raw->setStyleOverrides(
|
||||
&st::groupCallInviteMembersList,
|
||||
&st::groupCallMultiSelect);
|
||||
auto initBox = [=](not_null<PeerListBox*> box) {
|
||||
box->setTitle(tr::lng_group_call_invite_conf());
|
||||
raw->hasSelectedValue() | rpl::start_with_next([=](bool has) {
|
||||
box->clearButtons();
|
||||
if (has) {
|
||||
box->addButton(tr::lng_group_call_invite_button(), [=] {
|
||||
const auto call = weak.get();
|
||||
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));
|
||||
});
|
||||
}
|
||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||
}, box->lifetime());
|
||||
};
|
||||
return Box<PeerListBox>(std::move(controller), initBox);
|
||||
}
|
||||
|
||||
} // namespace Calls::Group
|
||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/peers/add_participants_box.h"
|
||||
|
||||
namespace Calls {
|
||||
class Call;
|
||||
class GroupCall;
|
||||
} // namespace Calls
|
||||
|
||||
|
@ -80,4 +81,9 @@ private:
|
|||
Fn<void(TextWithEntities&&)> showToast,
|
||||
Fn<void(Fn<void(bool)> finished)> shareConferenceLink = nullptr);
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||
not_null<Call*> call,
|
||||
Fn<void(std::vector<not_null<UserData*>>)> inviteUsers,
|
||||
Fn<void()> shareLink);
|
||||
|
||||
} // namespace Calls::Group
|
||||
|
|
|
@ -985,10 +985,10 @@ Fn<void(Fn<void(bool)> finished)> Panel::shareConferenceLinkCallback() {
|
|||
return;
|
||||
}
|
||||
*exporting = true;
|
||||
const auto done = [=](bool ok) {
|
||||
const auto done = [=](QString link) {
|
||||
*exporting = false;
|
||||
if (const auto onstack = finished) {
|
||||
onstack(ok);
|
||||
onstack(!link.isEmpty());
|
||||
}
|
||||
};
|
||||
ExportConferenceCallLink(uiShow(), _call->conferenceCall(), {
|
||||
|
@ -998,6 +998,21 @@ Fn<void(Fn<void(bool)> finished)> Panel::shareConferenceLinkCallback() {
|
|||
};
|
||||
}
|
||||
|
||||
void Panel::migrationShowShareLink() {
|
||||
ShowConferenceCallLinkBox(
|
||||
uiShow(),
|
||||
_call->conferenceCall(),
|
||||
_call->existingConferenceLink(),
|
||||
{ .st = DarkConferenceCallLinkStyle() });
|
||||
}
|
||||
|
||||
void Panel::migrationInviteUsers(std::vector<not_null<UserData*>> users) {
|
||||
const auto done = [=](GroupCall::InviteResult result) {
|
||||
showToast({ ComposeInviteResultToast(result) });
|
||||
};
|
||||
_call->inviteUsers(std::move(users), crl::guard(this, done));
|
||||
}
|
||||
|
||||
void Panel::enlargeVideo() {
|
||||
_lastSmallGeometry = window()->geometry();
|
||||
|
||||
|
|
|
@ -115,6 +115,9 @@ public:
|
|||
void hideLayer(anim::type animated = anim::type::normal);
|
||||
[[nodiscard]] bool isLayerShown() const;
|
||||
|
||||
void migrationShowShareLink();
|
||||
void migrationInviteUsers(std::vector<not_null<UserData*>> users);
|
||||
|
||||
void minimize();
|
||||
void toggleFullScreen();
|
||||
void close();
|
||||
|
|
|
@ -1342,7 +1342,7 @@ peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked;
|
|||
stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats;
|
||||
|
||||
groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall;
|
||||
groupCall#d597650c flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int = GroupCall;
|
||||
groupCall#d597650c flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int = GroupCall;
|
||||
|
||||
inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
|
||||
inputGroupCallSlug#fe06823f slug:string = InputGroupCall;
|
||||
|
|
|
@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "apiwrap.h"
|
||||
#include "base/event_filter.h"
|
||||
#include "base/qt_signal_producer.h"
|
||||
#include "base/random.h"
|
||||
#include "boxes/about_box.h"
|
||||
#include "boxes/peer_list_controllers.h"
|
||||
#include "boxes/premium_preview_box.h"
|
||||
|
@ -123,40 +122,23 @@ constexpr auto kPlayStatusLimit = 2;
|
|||
(height - st::inviteViaLinkIcon.height()) / 2);
|
||||
}, icon->lifetime());
|
||||
|
||||
const auto creating = std::make_shared<int32>();
|
||||
const auto creating = std::make_shared<bool>();
|
||||
result->setClickedCallback([=] {
|
||||
if (*creating) {
|
||||
return;
|
||||
}
|
||||
*creating = base::RandomValue<int32>();
|
||||
const auto show = controller->uiShow();
|
||||
const auto session = &controller->session();
|
||||
session->api().request(MTPphone_CreateConferenceCall(
|
||||
MTP_int(*creating)
|
||||
)).done(crl::guard(controller, [=](const MTPphone_GroupCall &result) {
|
||||
result.data().vcall().match([&](const auto &data) {
|
||||
const auto call = session->data().sharedConferenceCall(
|
||||
data.vid().v,
|
||||
data.vaccess_hash().v);
|
||||
call->processFullCall(result);
|
||||
const auto finished = [=](bool ok) {
|
||||
if (!ok) {
|
||||
*creating = 0;
|
||||
} else if (const auto onstack = done) {
|
||||
onstack();
|
||||
}
|
||||
};
|
||||
const auto show = controller->uiShow();
|
||||
Calls::Group::ExportConferenceCallLink(show, call, {
|
||||
.initial = true,
|
||||
.finished = finished,
|
||||
.weakWindow = controller,
|
||||
});
|
||||
});
|
||||
})).fail(crl::guard(controller, [=](const MTP::Error &error) {
|
||||
show->showToast(error.type());
|
||||
*creating = 0;
|
||||
})).send();
|
||||
*creating = true;
|
||||
const auto finished = [=](QString link) {
|
||||
if (link.isEmpty()) {
|
||||
*creating = false;
|
||||
} else if (const auto onstack = done) {
|
||||
onstack();
|
||||
}
|
||||
};
|
||||
Calls::Group::MakeConferenceCall({
|
||||
.show = controller->uiShow(),
|
||||
.finished = finished,
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -842,39 +842,20 @@ void SessionNavigation::resolveCollectible(
|
|||
|
||||
void SessionNavigation::resolveConferenceCall(
|
||||
QString slug,
|
||||
Fn<void(bool)> finished,
|
||||
bool skipConfirm) {
|
||||
resolveConferenceCall(
|
||||
std::move(slug),
|
||||
0,
|
||||
std::move(finished),
|
||||
skipConfirm);
|
||||
Fn<void(bool)> finished) {
|
||||
resolveConferenceCall(std::move(slug), 0, std::move(finished));
|
||||
}
|
||||
|
||||
void SessionNavigation::resolveConferenceCall(
|
||||
MsgId inviteMsgId,
|
||||
Fn<void(bool)> finished,
|
||||
bool skipConfirm) {
|
||||
resolveConferenceCall({}, inviteMsgId, std::move(finished), skipConfirm);
|
||||
Fn<void(bool)> finished) {
|
||||
resolveConferenceCall({}, inviteMsgId, std::move(finished));
|
||||
}
|
||||
|
||||
void SessionNavigation::resolveConferenceCall(
|
||||
QString slug,
|
||||
MsgId inviteMsgId,
|
||||
Fn<void(bool)> finished,
|
||||
bool skipConfirm) {
|
||||
// Accept tg://call?slug= links as well.
|
||||
const auto parts1 = QStringView(slug).split('#');
|
||||
if (!parts1.isEmpty()) {
|
||||
const auto parts2 = parts1.front().split('&');
|
||||
if (!parts2.isEmpty()) {
|
||||
const auto parts3 = parts2.front().split(u"slug="_q);
|
||||
if (parts3.size() > 1) {
|
||||
slug = parts3.back().toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Fn<void(bool)> finished) {
|
||||
_conferenceCallResolveFinished = std::move(finished);
|
||||
if (_conferenceCallSlug == slug
|
||||
&& _conferenceCallInviteMsgId == inviteMsgId) {
|
||||
|
@ -903,19 +884,12 @@ void SessionNavigation::resolveConferenceCall(
|
|||
const auto confirmed = std::make_shared<bool>();
|
||||
const auto join = [=] {
|
||||
*confirmed = true;
|
||||
Core::App().calls().startOrJoinConferenceCall(uiShow(), {
|
||||
Core::App().calls().startOrJoinConferenceCall({
|
||||
.call = call,
|
||||
.linkSlug = slug,
|
||||
.joinMessageId = inviteMsgId,
|
||||
});
|
||||
};
|
||||
if (skipConfirm) {
|
||||
join();
|
||||
if (finished) {
|
||||
finished(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const auto box = uiShow()->show(Box(
|
||||
Calls::Group::ConferenceCallJoinConfirm,
|
||||
call,
|
||||
|
|
|
@ -266,12 +266,10 @@ public:
|
|||
Fn<void(QString)> fail = nullptr);
|
||||
void resolveConferenceCall(
|
||||
QString slug,
|
||||
Fn<void(bool)> finished = nullptr,
|
||||
bool skipConfirm = false);
|
||||
Fn<void(bool)> finished = nullptr);
|
||||
void resolveConferenceCall(
|
||||
MsgId inviteMsgId,
|
||||
Fn<void(bool)> finished = nullptr,
|
||||
bool skipConfirm = false);
|
||||
Fn<void(bool)> finished = nullptr);
|
||||
|
||||
base::weak_ptr<Ui::Toast::Instance> showToast(
|
||||
Ui::Toast::Config &&config);
|
||||
|
@ -301,8 +299,7 @@ private:
|
|||
void resolveConferenceCall(
|
||||
QString slug,
|
||||
MsgId inviteMsgId,
|
||||
Fn<void(bool)> finished,
|
||||
bool skipConfirm);
|
||||
Fn<void(bool)> finished);
|
||||
|
||||
void resolveDone(
|
||||
const MTPcontacts_ResolvedPeer &result,
|
||||
|
|
Loading…
Add table
Reference in a new issue