mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 22:54:01 +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_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_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_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_bar_hangup" = "End call";
|
||||||
"lng_call_leave_to_other_sure" = "End your active call and join this video chat?";
|
"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_start_video" = "Start Video";
|
||||||
"lng_call_stop_video" = "Stop Video";
|
"lng_call_stop_video" = "Stop Video";
|
||||||
"lng_call_screencast" = "Screencast";
|
"lng_call_screencast" = "Screencast";
|
||||||
|
"lng_call_add_people" = "Add People";
|
||||||
"lng_call_end_call" = "End Call";
|
"lng_call_end_call" = "End Call";
|
||||||
"lng_call_mute_audio" = "Mute";
|
"lng_call_mute_audio" = "Mute";
|
||||||
"lng_call_unmute_audio" = "Unmute";
|
"lng_call_unmute_audio" = "Unmute";
|
||||||
|
|
|
@ -24,7 +24,7 @@ CallSignalBars {
|
||||||
inactiveOpacity: double;
|
inactiveOpacity: double;
|
||||||
}
|
}
|
||||||
|
|
||||||
callWidthMin: 300px;
|
callWidthMin: 372px;
|
||||||
callHeightMin: 440px;
|
callHeightMin: 440px;
|
||||||
callWidth: 720px;
|
callWidth: 720px;
|
||||||
callHeight: 540px;
|
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 {
|
callCornerButtonInner: IconButton {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "calls/calls_panel.h"
|
#include "calls/calls_panel.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/core_settings.h"
|
#include "core/core_settings.h"
|
||||||
|
#include "data/data_group_call.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
@ -527,20 +528,23 @@ crl::time Call::getDurationMs() const {
|
||||||
return _startTime ? (crl::now() - _startTime) : 0;
|
return _startTime ? (crl::now() - _startTime) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Call::hangup() {
|
void Call::hangup(Data::GroupCall *migrateCall, const QString &migrateSlug) {
|
||||||
const auto state = _state.current();
|
const auto state = _state.current();
|
||||||
if (state == State::Busy) {
|
if (state == State::Busy || state == State::MigrationHangingUp) {
|
||||||
_delegate->callFinished(this);
|
_delegate->callFinished(this);
|
||||||
} else {
|
} else {
|
||||||
const auto missed = (state == State::Ringing
|
const auto missed = (state == State::Ringing
|
||||||
|| (state == State::Waiting && _type == Type::Outgoing));
|
|| (state == State::Waiting && _type == Type::Outgoing));
|
||||||
const auto declined = isIncomingWaiting();
|
const auto declined = isIncomingWaiting();
|
||||||
const auto reason = missed
|
const auto reason = !migrateSlug.isEmpty()
|
||||||
|
? MTP_phoneCallDiscardReasonMigrateConferenceCall(
|
||||||
|
MTP_string(migrateSlug))
|
||||||
|
: missed
|
||||||
? MTP_phoneCallDiscardReasonMissed()
|
? MTP_phoneCallDiscardReasonMissed()
|
||||||
: declined
|
: declined
|
||||||
? MTP_phoneCallDiscardReasonBusy()
|
? MTP_phoneCallDiscardReasonBusy()
|
||||||
: MTP_phoneCallDiscardReasonHangup();
|
: 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) {
|
&& reason->type() == mtpc_phoneCallDiscardReasonDisconnect) {
|
||||||
LOG(("Call Info: Discarded with DISCONNECT reason."));
|
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);
|
setState(State::Busy);
|
||||||
} else if (_type == Type::Outgoing
|
} else if (_type == Type::Outgoing
|
||||||
|| _state.current() == State::HangingUp) {
|
|| _state.current() == State::HangingUp) {
|
||||||
|
@ -768,6 +775,32 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
|
||||||
Unexpected("phoneCall type inside an existing call handleUpdate()");
|
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(
|
void Call::updateRemoteMediaState(
|
||||||
tgcalls::AudioState audio,
|
tgcalls::AudioState audio,
|
||||||
tgcalls::VideoState video) {
|
tgcalls::VideoState video) {
|
||||||
|
@ -1059,6 +1092,7 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
|
||||||
const auto track = (state != State::FailedHangingUp)
|
const auto track = (state != State::FailedHangingUp)
|
||||||
&& (state != State::Failed)
|
&& (state != State::Failed)
|
||||||
&& (state != State::HangingUp)
|
&& (state != State::HangingUp)
|
||||||
|
&& (state != State::MigrationHangingUp)
|
||||||
&& (state != State::Ended)
|
&& (state != State::Ended)
|
||||||
&& (state != State::EndedByOtherDevice)
|
&& (state != State::EndedByOtherDevice)
|
||||||
&& (state != State::Busy);
|
&& (state != State::Busy);
|
||||||
|
@ -1175,6 +1209,11 @@ void Call::setState(State state) {
|
||||||
&& state != State::Failed) {
|
&& state != State::Failed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (was == State::MigrationHangingUp
|
||||||
|
&& state != State::Ended
|
||||||
|
&& state != State::Failed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (was != state) {
|
if (was != state) {
|
||||||
_state = state;
|
_state = state;
|
||||||
|
|
||||||
|
@ -1323,7 +1362,10 @@ rpl::producer<Webrtc::DeviceResolvedId> Call::cameraDeviceIdValue() const {
|
||||||
return _cameraDeviceId.value();
|
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);
|
Expects(type != FinishType::None);
|
||||||
|
|
||||||
setSignalBarCount(kSignalBarFinished);
|
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
|
// We want to discard request still being sent and processed even if
|
||||||
// the call is already destroyed.
|
// the call is already destroyed.
|
||||||
|
if (migrateCall) {
|
||||||
|
_user->owner().registerInvitedToCallUser(
|
||||||
|
migrateCall->id(),
|
||||||
|
migrateCall,
|
||||||
|
_user);
|
||||||
|
}
|
||||||
const auto session = &_user->session();
|
const auto session = &_user->session();
|
||||||
const auto weak = base::make_weak(this);
|
const auto weak = base::make_weak(this);
|
||||||
session->api().request(MTPphone_DiscardCall( // We send 'discard' here.
|
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 "mtproto/mtproto_auth_key.h"
|
||||||
#include "webrtc/webrtc_device_resolver.h"
|
#include "webrtc/webrtc_device_resolver.h"
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class GroupCall;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Audio {
|
namespace Audio {
|
||||||
class Track;
|
class Track;
|
||||||
|
@ -122,6 +126,7 @@ public:
|
||||||
FailedHangingUp,
|
FailedHangingUp,
|
||||||
Failed,
|
Failed,
|
||||||
HangingUp,
|
HangingUp,
|
||||||
|
MigrationHangingUp,
|
||||||
Ended,
|
Ended,
|
||||||
EndedByOtherDevice,
|
EndedByOtherDevice,
|
||||||
ExchangingKeys,
|
ExchangingKeys,
|
||||||
|
@ -198,7 +203,9 @@ public:
|
||||||
|
|
||||||
void applyUserConfirmation();
|
void applyUserConfirmation();
|
||||||
void answer();
|
void answer();
|
||||||
void hangup();
|
void hangup(
|
||||||
|
Data::GroupCall *migrateCall = nullptr,
|
||||||
|
const QString &migrateSlug = QString());
|
||||||
void redial();
|
void redial();
|
||||||
|
|
||||||
bool isKeyShaForFingerprintReady() const;
|
bool isKeyShaForFingerprintReady() const;
|
||||||
|
@ -246,7 +253,9 @@ private:
|
||||||
void finish(
|
void finish(
|
||||||
FinishType type,
|
FinishType type,
|
||||||
const MTPPhoneCallDiscardReason &reason
|
const MTPPhoneCallDiscardReason &reason
|
||||||
= MTP_phoneCallDiscardReasonDisconnect());
|
= MTP_phoneCallDiscardReasonDisconnect(),
|
||||||
|
Data::GroupCall *migrateCall = nullptr);
|
||||||
|
void finishByMigration(const QString &slug);
|
||||||
void startOutgoing();
|
void startOutgoing();
|
||||||
void startIncoming();
|
void startIncoming();
|
||||||
void startWaitingTrack();
|
void startWaitingTrack();
|
||||||
|
|
|
@ -230,12 +230,13 @@ void Instance::startOrJoinGroupCall(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::startOrJoinConferenceCall(
|
void Instance::startOrJoinConferenceCall(StartConferenceCallArgs args) {
|
||||||
std::shared_ptr<Ui::Show> show,
|
destroyCurrentCall(
|
||||||
StartConferenceCallArgs args) {
|
args.migrating ? args.call.get() : nullptr,
|
||||||
destroyCurrentCall();
|
args.migrating ? args.linkSlug : QString());
|
||||||
|
|
||||||
const auto session = &args.call->peer()->session();
|
const auto session = &args.call->peer()->session();
|
||||||
|
const auto showShareLink = args.migrating && args.invite.empty();
|
||||||
auto call = std::make_unique<GroupCall>(
|
auto call = std::make_unique<GroupCall>(
|
||||||
_delegate.get(),
|
_delegate.get(),
|
||||||
Calls::Group::ConferenceInfo{
|
Calls::Group::ConferenceInfo{
|
||||||
|
@ -254,6 +255,11 @@ void Instance::startOrJoinConferenceCall(
|
||||||
_currentGroupCallPanel = std::make_unique<Group::Panel>(raw);
|
_currentGroupCallPanel = std::make_unique<Group::Panel>(raw);
|
||||||
_currentGroupCall = std::move(call);
|
_currentGroupCall = std::move(call);
|
||||||
_currentGroupCallChanges.fire_copy(raw);
|
_currentGroupCallChanges.fire_copy(raw);
|
||||||
|
if (!args.invite.empty()) {
|
||||||
|
_currentGroupCallPanel->migrationInviteUsers(std::move(args.invite));
|
||||||
|
} else if (args.migrating) {
|
||||||
|
_currentGroupCallPanel->migrationShowShareLink();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::confirmLeaveCurrent(
|
void Instance::confirmLeaveCurrent(
|
||||||
|
@ -435,24 +441,6 @@ void Instance::createGroupCall(
|
||||||
_currentGroupCallChanges.fire_copy(raw);
|
_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() {
|
void Instance::refreshDhConfig() {
|
||||||
Expects(_currentCall != nullptr);
|
Expects(_currentCall != nullptr);
|
||||||
|
|
||||||
|
@ -744,9 +732,11 @@ bool Instance::inGroupCall() const {
|
||||||
&& (state != GroupCall::State::Failed);
|
&& (state != GroupCall::State::Failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::destroyCurrentCall() {
|
void Instance::destroyCurrentCall(
|
||||||
|
Data::GroupCall *migrateCall,
|
||||||
|
const QString &migrateSlug) {
|
||||||
if (const auto current = currentCall()) {
|
if (const auto current = currentCall()) {
|
||||||
current->hangup();
|
current->hangup(migrateCall, migrateSlug);
|
||||||
if (const auto still = currentCall()) {
|
if (const auto still = currentCall()) {
|
||||||
destroyCall(still);
|
destroyCall(still);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,8 @@ struct StartConferenceCallArgs {
|
||||||
std::shared_ptr<TdE2E::Call> e2e;
|
std::shared_ptr<TdE2E::Call> e2e;
|
||||||
QString linkSlug;
|
QString linkSlug;
|
||||||
MsgId joinMessageId;
|
MsgId joinMessageId;
|
||||||
|
std::vector<not_null<UserData*>> invite;
|
||||||
|
bool migrating = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Instance final : public base::has_weak_ptr {
|
class Instance final : public base::has_weak_ptr {
|
||||||
|
@ -85,9 +87,7 @@ public:
|
||||||
std::shared_ptr<Ui::Show> show,
|
std::shared_ptr<Ui::Show> show,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
StartGroupCallArgs args);
|
StartGroupCallArgs args);
|
||||||
void startOrJoinConferenceCall(
|
void startOrJoinConferenceCall(StartConferenceCallArgs args);
|
||||||
std::shared_ptr<Ui::Show> show,
|
|
||||||
StartConferenceCallArgs args);
|
|
||||||
void showStartWithRtmp(
|
void showStartWithRtmp(
|
||||||
std::shared_ptr<Ui::Show> show,
|
std::shared_ptr<Ui::Show> show,
|
||||||
not_null<PeerData*> peer);
|
not_null<PeerData*> peer);
|
||||||
|
@ -140,7 +140,6 @@ private:
|
||||||
void createGroupCall(
|
void createGroupCall(
|
||||||
Group::JoinInfo info,
|
Group::JoinInfo info,
|
||||||
const MTPInputGroupCall &inputCall);
|
const MTPInputGroupCall &inputCall);
|
||||||
void createConferenceCall(Group::ConferenceInfo info);
|
|
||||||
void destroyGroupCall(not_null<GroupCall*> call);
|
void destroyGroupCall(not_null<GroupCall*> call);
|
||||||
void confirmLeaveCurrent(
|
void confirmLeaveCurrent(
|
||||||
std::shared_ptr<Ui::Show> show,
|
std::shared_ptr<Ui::Show> show,
|
||||||
|
@ -156,7 +155,9 @@ private:
|
||||||
void refreshServerConfig(not_null<Main::Session*> session);
|
void refreshServerConfig(not_null<Main::Session*> session);
|
||||||
bytes::const_span updateDhConfig(const MTPmessages_DhConfig &data);
|
bytes::const_span updateDhConfig(const MTPmessages_DhConfig &data);
|
||||||
|
|
||||||
void destroyCurrentCall();
|
void destroyCurrentCall(
|
||||||
|
Data::GroupCall *migrateCall = nullptr,
|
||||||
|
const QString &migrateSlug = QString());
|
||||||
void handleCallUpdate(
|
void handleCallUpdate(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
const MTPPhoneCall &call);
|
const MTPPhoneCall &call);
|
||||||
|
|
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_cloud_file.h"
|
#include "data/data_cloud_file.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "calls/group/calls_group_common.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/ui/calls_device_menu.h"
|
||||||
#include "calls/calls_emoji_fingerprint.h"
|
#include "calls/calls_emoji_fingerprint.h"
|
||||||
#include "calls/calls_signal_bars.h"
|
#include "calls/calls_signal_bars.h"
|
||||||
|
@ -45,6 +46,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/integration.h"
|
#include "ui/integration.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
#include "main/session/session_show.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "platform/platform_specific.h"
|
#include "platform/platform_specific.h"
|
||||||
|
@ -92,6 +94,77 @@ constexpr auto kHideControlsQuickTimeout = 2 * crl::time(1000);
|
||||||
</svg>)";
|
</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
|
} // namespace
|
||||||
|
|
||||||
Panel::Panel(not_null<Call*> call)
|
Panel::Panel(not_null<Call*> call)
|
||||||
|
@ -121,6 +194,9 @@ Panel::Panel(not_null<Call*> call)
|
||||||
widget(),
|
widget(),
|
||||||
st::callMicrophoneMute,
|
st::callMicrophoneMute,
|
||||||
&st::callMicrophoneUnmute))
|
&st::callMicrophoneUnmute))
|
||||||
|
, _addPeople(
|
||||||
|
widget(),
|
||||||
|
object_ptr<Ui::CallButton>(widget(), st::callAddPeople))
|
||||||
, _name(widget(), st::callName)
|
, _name(widget(), st::callName)
|
||||||
, _status(widget(), st::callStatus)
|
, _status(widget(), st::callStatus)
|
||||||
, _hideControlsTimer([=] { requestControlsHidden(true); })
|
, _hideControlsTimer([=] { requestControlsHidden(true); })
|
||||||
|
@ -133,6 +209,8 @@ Panel::Panel(not_null<Call*> call)
|
||||||
_cancel->setDuration(st::callPanelDuration);
|
_cancel->setDuration(st::callPanelDuration);
|
||||||
_cancel->entity()->setText(tr::lng_call_cancel());
|
_cancel->entity()->setText(tr::lng_call_cancel());
|
||||||
_screencast->setDuration(st::callPanelDuration);
|
_screencast->setDuration(st::callPanelDuration);
|
||||||
|
_addPeople->setDuration(st::callPanelDuration);
|
||||||
|
_addPeople->entity()->setText(tr::lng_call_add_people());
|
||||||
|
|
||||||
initWindow();
|
initWindow();
|
||||||
initWidget();
|
initWidget();
|
||||||
|
@ -153,6 +231,62 @@ bool Panel::isActive() const {
|
||||||
return window()->isActiveWindow() && isVisible();
|
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() {
|
void Panel::showAndActivate() {
|
||||||
if (window()->isHidden()) {
|
if (window()->isHidden()) {
|
||||||
window()->show();
|
window()->show();
|
||||||
|
@ -303,7 +437,7 @@ void Panel::initControls() {
|
||||||
return;
|
return;
|
||||||
} else if (!env->desktopCaptureAllowed()) {
|
} else if (!env->desktopCaptureAllowed()) {
|
||||||
if (auto box = Group::ScreenSharingPrivacyRequestBox()) {
|
if (auto box = Group::ScreenSharingPrivacyRequestBox()) {
|
||||||
_layerBg->showBox(std::move(box));
|
showBox(std::move(box));
|
||||||
}
|
}
|
||||||
} else if (const auto source = env->uniqueDesktopCaptureSource()) {
|
} else if (const auto source = env->uniqueDesktopCaptureSource()) {
|
||||||
if (!chooseSourceActiveDeviceId().isEmpty()) {
|
if (!chooseSourceActiveDeviceId().isEmpty()) {
|
||||||
|
@ -318,9 +452,42 @@ void Panel::initControls() {
|
||||||
_camera->setClickedCallback([=] {
|
_camera->setClickedCallback([=] {
|
||||||
if (!_call) {
|
if (!_call) {
|
||||||
return;
|
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] {
|
_updateDurationTimer.setCallback([this] {
|
||||||
|
@ -605,6 +772,7 @@ void Panel::reinitWithCall(Call *call) {
|
||||||
&& state != State::EndedByOtherDevice
|
&& state != State::EndedByOtherDevice
|
||||||
&& state != State::Failed
|
&& state != State::Failed
|
||||||
&& state != State::FailedHangingUp
|
&& state != State::FailedHangingUp
|
||||||
|
&& state != State::MigrationHangingUp
|
||||||
&& state != State::HangingUp) {
|
&& state != State::HangingUp) {
|
||||||
refreshOutgoingPreviewInBody(state);
|
refreshOutgoingPreviewInBody(state);
|
||||||
}
|
}
|
||||||
|
@ -630,10 +798,7 @@ void Panel::reinitWithCall(Call *call) {
|
||||||
}
|
}
|
||||||
Unexpected("Error type in _call->errors().");
|
Unexpected("Error type in _call->errors().");
|
||||||
}();
|
}();
|
||||||
Ui::Toast::Show(widget(), Ui::Toast::Config{
|
showToast(text);
|
||||||
.text = { text },
|
|
||||||
.st = &st::callErrorToast,
|
|
||||||
});
|
|
||||||
}, _callLifetime);
|
}, _callLifetime);
|
||||||
|
|
||||||
_name->setText(_user->name());
|
_name->setText(_user->name());
|
||||||
|
@ -647,6 +812,7 @@ void Panel::reinitWithCall(Call *call) {
|
||||||
_startVideo->raise();
|
_startVideo->raise();
|
||||||
}
|
}
|
||||||
_mute->raise();
|
_mute->raise();
|
||||||
|
_addPeople->raise();
|
||||||
|
|
||||||
_powerSaveBlocker = std::make_unique<base::PowerSaveBlocker>(
|
_powerSaveBlocker = std::make_unique<base::PowerSaveBlocker>(
|
||||||
base::PowerSaveBlockType::PreventDisplaySleep,
|
base::PowerSaveBlockType::PreventDisplaySleep,
|
||||||
|
@ -1077,11 +1243,7 @@ void Panel::updateHangupGeometry() {
|
||||||
// Screencast - Camera - Cancel/Decline - Answer/Hangup/Redial - Mute.
|
// Screencast - Camera - Cancel/Decline - Answer/Hangup/Redial - Mute.
|
||||||
const auto buttonWidth = st::callCancel.button.width;
|
const auto buttonWidth = st::callCancel.button.width;
|
||||||
const auto cancelWidth = buttonWidth * (1. - hangupProgress);
|
const auto cancelWidth = buttonWidth * (1. - hangupProgress);
|
||||||
const auto cancelLeft = (isWaitingUser)
|
const auto cancelLeft = (widget()->width() - buttonWidth) / 2;
|
||||||
? ((widget()->width() - buttonWidth) / 2)
|
|
||||||
: (_mute->animating())
|
|
||||||
? ((widget()->width() - cancelWidth) / 2)
|
|
||||||
: ((widget()->width() / 2) - cancelWidth);
|
|
||||||
|
|
||||||
_cancel->moveToLeft(cancelLeft, _buttonsTop);
|
_cancel->moveToLeft(cancelLeft, _buttonsTop);
|
||||||
_decline->moveToLeft(cancelLeft, _buttonsTop);
|
_decline->moveToLeft(cancelLeft, _buttonsTop);
|
||||||
|
@ -1089,6 +1251,7 @@ void Panel::updateHangupGeometry() {
|
||||||
_screencast->moveToLeft(_camera->x() - buttonWidth, _buttonsTop);
|
_screencast->moveToLeft(_camera->x() - buttonWidth, _buttonsTop);
|
||||||
_answerHangupRedial->moveToLeft(cancelLeft + cancelWidth, _buttonsTop);
|
_answerHangupRedial->moveToLeft(cancelLeft + cancelWidth, _buttonsTop);
|
||||||
_mute->moveToLeft(_answerHangupRedial->x() + buttonWidth, _buttonsTop);
|
_mute->moveToLeft(_answerHangupRedial->x() + buttonWidth, _buttonsTop);
|
||||||
|
_addPeople->moveToLeft(_mute->x() + buttonWidth, _buttonsTop);
|
||||||
if (_startVideo) {
|
if (_startVideo) {
|
||||||
_startVideo->moveToLeft(_camera->x(), _camera->y());
|
_startVideo->moveToLeft(_camera->x(), _camera->y());
|
||||||
}
|
}
|
||||||
|
@ -1136,12 +1299,17 @@ not_null<Ui::RpWidget*> Panel::widget() const {
|
||||||
return _window.widget();
|
return _window.widget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_null<UserData*> Panel::user() const {
|
||||||
|
return _user;
|
||||||
|
}
|
||||||
|
|
||||||
void Panel::stateChanged(State state) {
|
void Panel::stateChanged(State state) {
|
||||||
Expects(_call != nullptr);
|
Expects(_call != nullptr);
|
||||||
|
|
||||||
updateStatusText(state);
|
updateStatusText(state);
|
||||||
|
|
||||||
if ((state != State::HangingUp)
|
if ((state != State::HangingUp)
|
||||||
|
&& (state != State::MigrationHangingUp)
|
||||||
&& (state != State::Ended)
|
&& (state != State::Ended)
|
||||||
&& (state != State::EndedByOtherDevice)
|
&& (state != State::EndedByOtherDevice)
|
||||||
&& (state != State::FailedHangingUp)
|
&& (state != State::FailedHangingUp)
|
||||||
|
@ -1182,6 +1350,7 @@ void Panel::stateChanged(State state) {
|
||||||
toggleButton(
|
toggleButton(
|
||||||
_screencast,
|
_screencast,
|
||||||
!(isBusy || isWaitingUser || incomingWaiting));
|
!(isBusy || isWaitingUser || incomingWaiting));
|
||||||
|
toggleButton(_addPeople, !isWaitingUser);
|
||||||
const auto hangupShown = !_decline->toggled()
|
const auto hangupShown = !_decline->toggled()
|
||||||
&& !_cancel->toggled();
|
&& !_cancel->toggled();
|
||||||
if (_hangupShown != hangupShown) {
|
if (_hangupShown != hangupShown) {
|
||||||
|
@ -1232,7 +1401,8 @@ void Panel::updateStatusText(State state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case State::Starting:
|
case State::Starting:
|
||||||
case State::WaitingInit:
|
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: {
|
case State::Established: {
|
||||||
if (_call) {
|
if (_call) {
|
||||||
auto durationMs = _call->getDurationMs();
|
auto durationMs = _call->getDurationMs();
|
||||||
|
|
|
@ -27,7 +27,15 @@ namespace Data {
|
||||||
class PhotoMedia;
|
class PhotoMedia;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace Main {
|
||||||
|
class SessionShow;
|
||||||
|
} // namespace Main
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
class BoxContent;
|
||||||
|
class LayerWidget;
|
||||||
|
enum class LayerOption;
|
||||||
|
using LayerOptions = base::flags<LayerOption>;
|
||||||
class IconButton;
|
class IconButton;
|
||||||
class CallButton;
|
class CallButton;
|
||||||
class LayerManager;
|
class LayerManager;
|
||||||
|
@ -38,14 +46,17 @@ template <typename Widget>
|
||||||
class PaddingWrap;
|
class PaddingWrap;
|
||||||
class RpWindow;
|
class RpWindow;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
namespace GL {
|
|
||||||
enum class Backend;
|
|
||||||
} // namespace GL
|
|
||||||
namespace Platform {
|
|
||||||
struct SeparateTitleControls;
|
|
||||||
} // namespace Platform
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Ui::Toast {
|
||||||
|
class Instance;
|
||||||
|
struct Config;
|
||||||
|
} // namespace Ui::Toast
|
||||||
|
|
||||||
|
namespace Ui::Platform {
|
||||||
|
struct SeparateTitleControls;
|
||||||
|
} // namespace Ui::Platform
|
||||||
|
|
||||||
namespace style {
|
namespace style {
|
||||||
struct CallSignalBars;
|
struct CallSignalBars;
|
||||||
struct CallBodyLayout;
|
struct CallBodyLayout;
|
||||||
|
@ -58,13 +69,39 @@ class SignalBars;
|
||||||
class VideoBubble;
|
class VideoBubble;
|
||||||
struct DeviceSelection;
|
struct DeviceSelection;
|
||||||
|
|
||||||
class Panel final : private Group::Ui::DesktopCapture::ChooseSourceDelegate {
|
class Panel final
|
||||||
|
: public base::has_weak_ptr
|
||||||
|
, private Group::Ui::DesktopCapture::ChooseSourceDelegate {
|
||||||
public:
|
public:
|
||||||
Panel(not_null<Call*> call);
|
Panel(not_null<Call*> call);
|
||||||
~Panel();
|
~Panel();
|
||||||
|
|
||||||
|
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
|
||||||
|
[[nodiscard]] not_null<UserData*> user() const;
|
||||||
[[nodiscard]] bool isVisible() const;
|
[[nodiscard]] bool isVisible() const;
|
||||||
[[nodiscard]] bool isActive() 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 showAndActivate();
|
||||||
void minimize();
|
void minimize();
|
||||||
void toggleFullScreen();
|
void toggleFullScreen();
|
||||||
|
@ -83,6 +120,8 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<bool> startOutgoingRequests() const;
|
[[nodiscard]] rpl::producer<bool> startOutgoingRequests() const;
|
||||||
|
|
||||||
|
[[nodiscard]] std::shared_ptr<Main::SessionShow> uiShow();
|
||||||
|
|
||||||
[[nodiscard]] rpl::lifetime &lifetime();
|
[[nodiscard]] rpl::lifetime &lifetime();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -97,7 +136,6 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] not_null<Ui::RpWindow*> window() const;
|
[[nodiscard]] not_null<Ui::RpWindow*> window() const;
|
||||||
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
|
|
||||||
|
|
||||||
void paint(QRect clip);
|
void paint(QRect clip);
|
||||||
|
|
||||||
|
@ -170,6 +208,7 @@ private:
|
||||||
base::unique_qptr<Ui::CallButton> _startVideo;
|
base::unique_qptr<Ui::CallButton> _startVideo;
|
||||||
object_ptr<Ui::FadeWrap<Ui::CallButton>> _mute;
|
object_ptr<Ui::FadeWrap<Ui::CallButton>> _mute;
|
||||||
Ui::CallButton *_audioDeviceToggle = nullptr;
|
Ui::CallButton *_audioDeviceToggle = nullptr;
|
||||||
|
object_ptr < Ui::FadeWrap<Ui::CallButton>> _addPeople;
|
||||||
object_ptr<Ui::FlatLabel> _name;
|
object_ptr<Ui::FlatLabel> _name;
|
||||||
object_ptr<Ui::FlatLabel> _status;
|
object_ptr<Ui::FlatLabel> _status;
|
||||||
object_ptr<Ui::RpWidget> _fingerprint = { nullptr };
|
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_keys.h"
|
||||||
#include "lang/lang_hardcoded.h"
|
#include "lang/lang_hardcoded.h"
|
||||||
#include "boxes/peers/edit_participants_box.h" // SubscribeToMigration.
|
#include "boxes/peers/edit_participants_box.h" // SubscribeToMigration.
|
||||||
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
|
@ -1164,6 +1165,15 @@ std::shared_ptr<Data::GroupCall> GroupCall::conferenceCall() const {
|
||||||
return _conferenceCall;
|
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 {
|
rpl::producer<not_null<Data::GroupCall*>> GroupCall::real() const {
|
||||||
if (const auto real = lookupReal()) {
|
if (const auto real = lookupReal()) {
|
||||||
return rpl::single(not_null{ real });
|
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
|
} // namespace Calls
|
||||||
|
|
|
@ -257,6 +257,7 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] Data::GroupCall *lookupReal() const;
|
[[nodiscard]] Data::GroupCall *lookupReal() const;
|
||||||
[[nodiscard]] std::shared_ptr<Data::GroupCall> conferenceCall() 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<not_null<Data::GroupCall*>> real() const;
|
||||||
[[nodiscard]] rpl::producer<QByteArray> emojiHashValue() const;
|
[[nodiscard]] rpl::producer<QByteArray> emojiHashValue() const;
|
||||||
|
|
||||||
|
@ -752,4 +753,7 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] TextWithEntities ComposeInviteResultToast(
|
||||||
|
const GroupCall::InviteResult &result);
|
||||||
|
|
||||||
} // namespace Calls
|
} // namespace Calls
|
||||||
|
|
|
@ -9,9 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
|
#include "base/random.h"
|
||||||
#include "boxes/share_box.h"
|
#include "boxes/share_box.h"
|
||||||
|
#include "calls/calls_instance.h"
|
||||||
|
#include "core/application.h"
|
||||||
#include "core/local_url_handlers.h"
|
#include "core/local_url_handlers.h"
|
||||||
#include "data/data_group_call.h"
|
#include "data/data_group_call.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
#include "info/bot/starref/info_bot_starref_common.h"
|
#include "info/bot/starref/info_bot_starref_common.h"
|
||||||
#include "ui/boxes/boost_box.h"
|
#include "ui/boxes/boost_box.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
@ -31,6 +35,24 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include <QtGui/QClipboard>
|
#include <QtGui/QClipboard>
|
||||||
|
|
||||||
namespace Calls::Group {
|
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() {
|
object_ptr<Ui::GenericBox> ScreenSharingPrivacyRequestBox() {
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
|
@ -107,7 +129,6 @@ void ShowConferenceCallLinkBox(
|
||||||
ConferenceCallLinkArgs &&args) {
|
ConferenceCallLinkArgs &&args) {
|
||||||
const auto st = args.st;
|
const auto st = args.st;
|
||||||
const auto initial = args.initial;
|
const auto initial = args.initial;
|
||||||
const auto weakWindow = args.weakWindow;
|
|
||||||
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
show->showBox(Box([=](not_null<Ui::GenericBox*> box) {
|
||||||
box->setStyle(st.box
|
box->setStyle(st.box
|
||||||
? *st.box
|
? *st.box
|
||||||
|
@ -151,7 +172,7 @@ void ShowConferenceCallLinkBox(
|
||||||
|
|
||||||
const auto copyCallback = [=] {
|
const auto copyCallback = [=] {
|
||||||
QApplication::clipboard()->setText(link);
|
QApplication::clipboard()->setText(link);
|
||||||
box->uiShow()->showToast(tr::lng_username_copied(tr::now));
|
show->showToast(tr::lng_username_copied(tr::now));
|
||||||
};
|
};
|
||||||
const auto shareCallback = [=] {
|
const auto shareCallback = [=] {
|
||||||
FastShareLink(
|
FastShareLink(
|
||||||
|
@ -218,12 +239,11 @@ void ShowConferenceCallLinkBox(
|
||||||
: st::confcallLinkCenteredText));
|
: st::confcallLinkCenteredText));
|
||||||
footer->setTryMakeSimilarLines(true);
|
footer->setTryMakeSimilarLines(true);
|
||||||
footer->setClickHandlerFilter([=](const auto &...) {
|
footer->setClickHandlerFilter([=](const auto &...) {
|
||||||
const auto local = Core::TryConvertUrlToLocal(link);
|
if (auto slug = ExtractConferenceSlug(link); !slug.isEmpty()) {
|
||||||
if (const auto controller = weakWindow.get()) {
|
Core::App().calls().startOrJoinConferenceCall({
|
||||||
controller->resolveConferenceCall(
|
.call = call,
|
||||||
local,
|
.linkSlug = std::move(slug),
|
||||||
crl::guard(box, [=](bool ok) { if (ok) box->closeBox(); }),
|
});
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -251,6 +271,7 @@ void ExportConferenceCallLink(
|
||||||
std::shared_ptr<Data::GroupCall> call,
|
std::shared_ptr<Data::GroupCall> call,
|
||||||
ConferenceCallLinkArgs &&args) {
|
ConferenceCallLinkArgs &&args) {
|
||||||
const auto session = &show->session();
|
const auto session = &show->session();
|
||||||
|
const auto invite = std::move(args.invite);
|
||||||
const auto finished = std::move(args.finished);
|
const auto finished = std::move(args.finished);
|
||||||
|
|
||||||
using Flag = MTPphone_ExportGroupCallInvite::Flag;
|
using Flag = MTPphone_ExportGroupCallInvite::Flag;
|
||||||
|
@ -259,18 +280,63 @@ void ExportConferenceCallLink(
|
||||||
call->input()
|
call->input()
|
||||||
)).done([=](const MTPphone_ExportedGroupCallInvite &result) {
|
)).done([=](const MTPphone_ExportedGroupCallInvite &result) {
|
||||||
const auto link = qs(result.data().vlink());
|
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(
|
Calls::Group::ShowConferenceCallLinkBox(
|
||||||
show,
|
show,
|
||||||
call,
|
call,
|
||||||
link,
|
link,
|
||||||
base::duplicate(args));
|
base::duplicate(args));
|
||||||
if (const auto onstack = finished) {
|
if (const auto onstack = finished) {
|
||||||
finished(true);
|
finished(link);
|
||||||
}
|
}
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
show->showToast(error.type());
|
show->showToast(error.type());
|
||||||
if (const auto onstack = finished) {
|
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();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,8 +142,10 @@ struct ConferenceCallLinkStyleOverrides {
|
||||||
|
|
||||||
struct ConferenceCallLinkArgs {
|
struct ConferenceCallLinkArgs {
|
||||||
bool initial = false;
|
bool initial = false;
|
||||||
Fn<void(bool)> finished;
|
bool joining = false;
|
||||||
base::weak_ptr<Window::SessionController> weakWindow = nullptr;
|
bool migrating = false;
|
||||||
|
Fn<void(QString)> finished;
|
||||||
|
std::vector<not_null<UserData*>> invite;
|
||||||
ConferenceCallLinkStyleOverrides st;
|
ConferenceCallLinkStyleOverrides st;
|
||||||
};
|
};
|
||||||
void ShowConferenceCallLinkBox(
|
void ShowConferenceCallLinkBox(
|
||||||
|
@ -157,4 +159,13 @@ void ExportConferenceCallLink(
|
||||||
std::shared_ptr<Data::GroupCall> call,
|
std::shared_ptr<Data::GroupCall> call,
|
||||||
ConferenceCallLinkArgs &&args);
|
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
|
} // namespace Calls::Group
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "api/api_chat_participants.h"
|
#include "api/api_chat_participants.h"
|
||||||
#include "calls/group/calls_group_call.h"
|
#include "calls/group/calls_group_call.h"
|
||||||
#include "calls/group/calls_group_menu.h"
|
#include "calls/group/calls_group_menu.h"
|
||||||
|
#include "calls/calls_call.h"
|
||||||
#include "boxes/peer_lists_box.h"
|
#include "boxes/peer_lists_box.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
@ -80,7 +81,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] int fullCount() const;
|
[[nodiscard]] int fullCount() const;
|
||||||
|
|
||||||
base::flat_set<not_null<UserData*>> _alreadyIn;
|
const base::flat_set<not_null<UserData*>> _alreadyIn;
|
||||||
const Fn<void()> _shareLink;
|
const Fn<void()> _shareLink;
|
||||||
rpl::variable<bool> _hasSelected;
|
rpl::variable<bool> _hasSelected;
|
||||||
|
|
||||||
|
@ -93,7 +94,6 @@ ConfInviteController::ConfInviteController(
|
||||||
: ContactsBoxController(session)
|
: ContactsBoxController(session)
|
||||||
, _alreadyIn(std::move(alreadyIn))
|
, _alreadyIn(std::move(alreadyIn))
|
||||||
, _shareLink(std::move(shareLink)) {
|
, _shareLink(std::move(shareLink)) {
|
||||||
_alreadyIn.remove(session->user());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<bool> ConfInviteController::hasSelectedValue() const {
|
rpl::producer<bool> ConfInviteController::hasSelectedValue() const {
|
||||||
|
@ -161,43 +161,6 @@ void ConfInviteController::prepareViewHook() {
|
||||||
delegate()->peerListSetAboveWidget(std::move(button));
|
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
|
} // namespace
|
||||||
|
|
||||||
InviteController::InviteController(
|
InviteController::InviteController(
|
||||||
|
@ -494,4 +457,44 @@ object_ptr<Ui::BoxContent> PrepareInviteBox(
|
||||||
return Box<PeerListsBox>(std::move(controllers), initBox);
|
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
|
} // namespace Calls::Group
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "boxes/peers/add_participants_box.h"
|
#include "boxes/peers/add_participants_box.h"
|
||||||
|
|
||||||
namespace Calls {
|
namespace Calls {
|
||||||
|
class Call;
|
||||||
class GroupCall;
|
class GroupCall;
|
||||||
} // namespace Calls
|
} // namespace Calls
|
||||||
|
|
||||||
|
@ -80,4 +81,9 @@ private:
|
||||||
Fn<void(TextWithEntities&&)> showToast,
|
Fn<void(TextWithEntities&&)> showToast,
|
||||||
Fn<void(Fn<void(bool)> finished)> shareConferenceLink = nullptr);
|
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
|
} // namespace Calls::Group
|
||||||
|
|
|
@ -985,10 +985,10 @@ Fn<void(Fn<void(bool)> finished)> Panel::shareConferenceLinkCallback() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*exporting = true;
|
*exporting = true;
|
||||||
const auto done = [=](bool ok) {
|
const auto done = [=](QString link) {
|
||||||
*exporting = false;
|
*exporting = false;
|
||||||
if (const auto onstack = finished) {
|
if (const auto onstack = finished) {
|
||||||
onstack(ok);
|
onstack(!link.isEmpty());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
ExportConferenceCallLink(uiShow(), _call->conferenceCall(), {
|
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() {
|
void Panel::enlargeVideo() {
|
||||||
_lastSmallGeometry = window()->geometry();
|
_lastSmallGeometry = window()->geometry();
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,9 @@ public:
|
||||||
void hideLayer(anim::type animated = anim::type::normal);
|
void hideLayer(anim::type animated = anim::type::normal);
|
||||||
[[nodiscard]] bool isLayerShown() const;
|
[[nodiscard]] bool isLayerShown() const;
|
||||||
|
|
||||||
|
void migrationShowShareLink();
|
||||||
|
void migrationInviteUsers(std::vector<not_null<UserData*>> users);
|
||||||
|
|
||||||
void minimize();
|
void minimize();
|
||||||
void toggleFullScreen();
|
void toggleFullScreen();
|
||||||
void close();
|
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;
|
stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats;
|
||||||
|
|
||||||
groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall;
|
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;
|
inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
|
||||||
inputGroupCallSlug#fe06823f slug:string = InputGroupCall;
|
inputGroupCallSlug#fe06823f slug:string = InputGroupCall;
|
||||||
|
|
|
@ -10,7 +10,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "base/event_filter.h"
|
#include "base/event_filter.h"
|
||||||
#include "base/qt_signal_producer.h"
|
#include "base/qt_signal_producer.h"
|
||||||
#include "base/random.h"
|
|
||||||
#include "boxes/about_box.h"
|
#include "boxes/about_box.h"
|
||||||
#include "boxes/peer_list_controllers.h"
|
#include "boxes/peer_list_controllers.h"
|
||||||
#include "boxes/premium_preview_box.h"
|
#include "boxes/premium_preview_box.h"
|
||||||
|
@ -123,40 +122,23 @@ constexpr auto kPlayStatusLimit = 2;
|
||||||
(height - st::inviteViaLinkIcon.height()) / 2);
|
(height - st::inviteViaLinkIcon.height()) / 2);
|
||||||
}, icon->lifetime());
|
}, icon->lifetime());
|
||||||
|
|
||||||
const auto creating = std::make_shared<int32>();
|
const auto creating = std::make_shared<bool>();
|
||||||
result->setClickedCallback([=] {
|
result->setClickedCallback([=] {
|
||||||
if (*creating) {
|
if (*creating) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*creating = base::RandomValue<int32>();
|
*creating = true;
|
||||||
const auto show = controller->uiShow();
|
const auto finished = [=](QString link) {
|
||||||
const auto session = &controller->session();
|
if (link.isEmpty()) {
|
||||||
session->api().request(MTPphone_CreateConferenceCall(
|
*creating = false;
|
||||||
MTP_int(*creating)
|
} else if (const auto onstack = done) {
|
||||||
)).done(crl::guard(controller, [=](const MTPphone_GroupCall &result) {
|
onstack();
|
||||||
result.data().vcall().match([&](const auto &data) {
|
}
|
||||||
const auto call = session->data().sharedConferenceCall(
|
};
|
||||||
data.vid().v,
|
Calls::Group::MakeConferenceCall({
|
||||||
data.vaccess_hash().v);
|
.show = controller->uiShow(),
|
||||||
call->processFullCall(result);
|
.finished = finished,
|
||||||
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();
|
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -842,39 +842,20 @@ void SessionNavigation::resolveCollectible(
|
||||||
|
|
||||||
void SessionNavigation::resolveConferenceCall(
|
void SessionNavigation::resolveConferenceCall(
|
||||||
QString slug,
|
QString slug,
|
||||||
Fn<void(bool)> finished,
|
Fn<void(bool)> finished) {
|
||||||
bool skipConfirm) {
|
resolveConferenceCall(std::move(slug), 0, std::move(finished));
|
||||||
resolveConferenceCall(
|
|
||||||
std::move(slug),
|
|
||||||
0,
|
|
||||||
std::move(finished),
|
|
||||||
skipConfirm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionNavigation::resolveConferenceCall(
|
void SessionNavigation::resolveConferenceCall(
|
||||||
MsgId inviteMsgId,
|
MsgId inviteMsgId,
|
||||||
Fn<void(bool)> finished,
|
Fn<void(bool)> finished) {
|
||||||
bool skipConfirm) {
|
resolveConferenceCall({}, inviteMsgId, std::move(finished));
|
||||||
resolveConferenceCall({}, inviteMsgId, std::move(finished), skipConfirm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SessionNavigation::resolveConferenceCall(
|
void SessionNavigation::resolveConferenceCall(
|
||||||
QString slug,
|
QString slug,
|
||||||
MsgId inviteMsgId,
|
MsgId inviteMsgId,
|
||||||
Fn<void(bool)> finished,
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_conferenceCallResolveFinished = std::move(finished);
|
_conferenceCallResolveFinished = std::move(finished);
|
||||||
if (_conferenceCallSlug == slug
|
if (_conferenceCallSlug == slug
|
||||||
&& _conferenceCallInviteMsgId == inviteMsgId) {
|
&& _conferenceCallInviteMsgId == inviteMsgId) {
|
||||||
|
@ -903,19 +884,12 @@ void SessionNavigation::resolveConferenceCall(
|
||||||
const auto confirmed = std::make_shared<bool>();
|
const auto confirmed = std::make_shared<bool>();
|
||||||
const auto join = [=] {
|
const auto join = [=] {
|
||||||
*confirmed = true;
|
*confirmed = true;
|
||||||
Core::App().calls().startOrJoinConferenceCall(uiShow(), {
|
Core::App().calls().startOrJoinConferenceCall({
|
||||||
.call = call,
|
.call = call,
|
||||||
.linkSlug = slug,
|
.linkSlug = slug,
|
||||||
.joinMessageId = inviteMsgId,
|
.joinMessageId = inviteMsgId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
if (skipConfirm) {
|
|
||||||
join();
|
|
||||||
if (finished) {
|
|
||||||
finished(true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto box = uiShow()->show(Box(
|
const auto box = uiShow()->show(Box(
|
||||||
Calls::Group::ConferenceCallJoinConfirm,
|
Calls::Group::ConferenceCallJoinConfirm,
|
||||||
call,
|
call,
|
||||||
|
|
|
@ -266,12 +266,10 @@ public:
|
||||||
Fn<void(QString)> fail = nullptr);
|
Fn<void(QString)> fail = nullptr);
|
||||||
void resolveConferenceCall(
|
void resolveConferenceCall(
|
||||||
QString slug,
|
QString slug,
|
||||||
Fn<void(bool)> finished = nullptr,
|
Fn<void(bool)> finished = nullptr);
|
||||||
bool skipConfirm = false);
|
|
||||||
void resolveConferenceCall(
|
void resolveConferenceCall(
|
||||||
MsgId inviteMsgId,
|
MsgId inviteMsgId,
|
||||||
Fn<void(bool)> finished = nullptr,
|
Fn<void(bool)> finished = nullptr);
|
||||||
bool skipConfirm = false);
|
|
||||||
|
|
||||||
base::weak_ptr<Ui::Toast::Instance> showToast(
|
base::weak_ptr<Ui::Toast::Instance> showToast(
|
||||||
Ui::Toast::Config &&config);
|
Ui::Toast::Config &&config);
|
||||||
|
@ -301,8 +299,7 @@ private:
|
||||||
void resolveConferenceCall(
|
void resolveConferenceCall(
|
||||||
QString slug,
|
QString slug,
|
||||||
MsgId inviteMsgId,
|
MsgId inviteMsgId,
|
||||||
Fn<void(bool)> finished,
|
Fn<void(bool)> finished);
|
||||||
bool skipConfirm);
|
|
||||||
|
|
||||||
void resolveDone(
|
void resolveDone(
|
||||||
const MTPcontacts_ResolvedPeer &result,
|
const MTPcontacts_ResolvedPeer &result,
|
||||||
|
|
Loading…
Add table
Reference in a new issue