Join other calls with confirmation.

This commit is contained in:
John Preston 2020-12-08 19:09:13 +04:00
parent 529c12ea3a
commit 546881c720
11 changed files with 119 additions and 58 deletions

View File

@ -1777,6 +1777,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_call_error_audio_io" = "There seems to be a problem with audio playback on your computer. Please make sure that your computer's speakers and microphone are working and try again.";
"lng_call_bar_hangup" = "End call";
"lng_call_leave_to_other_sure" = "Do you want to end your active call and join a voice chat in this group?";
"lng_call_box_title" = "Calls";
"lng_call_box_about" = "You haven't made any Telegram calls yet.";
@ -1824,6 +1825,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_leave" = "Leave";
"lng_group_call_leave_title" = "Leave voice chat";
"lng_group_call_leave_sure" = "Are you sure you want to leave this voice chat?";
"lng_group_call_leave_to_other_sure" = "Do you want to leave your active voice chat and join a voice chat in this group?";
"lng_group_call_also_end" = "End voice chat";
"lng_group_call_settings_title" = "Settings";
"lng_group_call_invite_title" = "Invite members";

View File

@ -1036,7 +1036,12 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
|| (_videoOutgoing->state() != Webrtc::VideoState::Inactive))
? MTPphone_DiscardCall::Flag::f_video
: MTPphone_DiscardCall::Flag(0);
_api.request(MTPphone_DiscardCall(
// We want to discard request still being sent and processed even if
// the call is already destroyed.
const auto session = &_user->session();
const auto weak = base::make_weak(this);
session->api().request(MTPphone_DiscardCall( // We send 'discard' here.
MTP_flags(flags),
MTP_inputPhoneCall(
MTP_long(_id),
@ -1047,11 +1052,11 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
)).done([=](const MTPUpdates &result) {
// Here 'this' could be destroyed by updates, so we set Ended after
// updates being handled, but in a guarded way.
crl::on_main(this, [=] { setState(finalState); });
_user->session().api().applyUpdates(result);
}).fail([this, finalState](const RPCError &error) {
crl::on_main(weak, [=] { setState(finalState); });
session->api().applyUpdates(result);
}).fail(crl::guard(weak, [this, finalState](const RPCError &error) {
setState(finalState);
}).send();
})).send();
}
void Call::setStateQueued(State state) {

View File

@ -330,17 +330,22 @@ void GroupCall::finish(FinishType type) {
}
setState(hangupState);
_api.request(MTPphone_LeaveGroupCall(
// We want to leave request still being sent and processed even if
// the call is already destroyed.
const auto session = &_channel->session();
const auto weak = base::make_weak(this);
session->api().request(MTPphone_LeaveGroupCall(
inputCall(),
MTP_int(_mySsrc)
)).done([=](const MTPUpdates &result) {
// Here 'this' could be destroyed by updates, so we set Ended after
// updates being handled, but in a guarded way.
crl::on_main(this, [=] { setState(finalState); });
_channel->session().api().applyUpdates(result);
}).fail([=](const RPCError &error) {
crl::on_main(weak, [=] { setState(finalState); });
session->api().applyUpdates(result);
}).fail(crl::guard(weak, [=](const RPCError &error) {
setState(finalState);
}).send();
})).send();
}
void GroupCall::setMuted(MuteState mute) {

View File

@ -58,23 +58,13 @@ void Instance::startOutgoingCall(not_null<UserData*> user, bool video) {
}), video);
}
void Instance::startGroupCall(not_null<ChannelData*> channel) {
if (activateCurrentCall()) {
return;
}
void Instance::startOrJoinGroupCall(not_null<ChannelData*> channel) {
destroyCurrentCall();
requestPermissionsOrFail(crl::guard(this, [=] {
createGroupCall(channel, MTP_inputGroupCall(MTPlong(), MTPlong()));
}), false);
}
void Instance::joinGroupCall(
not_null<ChannelData*> channel,
const MTPInputGroupCall &call) {
if (activateCurrentCall()) {
return;
}
requestPermissionsOrFail(crl::guard(this, [=] {
createGroupCall(channel, call);
const auto call = channel->call();
createGroupCall(
channel,
call ? call->input() : MTP_inputGroupCall(MTPlong(), MTPlong()));
}), false);
}
@ -432,7 +422,11 @@ void Instance::handleSignalingData(
}
bool Instance::inCall() const {
return (_currentCall && _currentCall->state() != Call::State::Busy);
if (!_currentCall) {
return false;
}
const auto state = _currentCall->state();
return (state != Call::State::Busy);
}
bool Instance::inGroupCall() const {
@ -446,6 +440,21 @@ bool Instance::inGroupCall() const {
&& (state != GroupCall::State::Failed);
}
void Instance::destroyCurrentCall() {
if (const auto current = currentCall()) {
current->hangup();
if (const auto still = currentCall()) {
destroyCall(still);
}
}
if (const auto current = currentGroupCall()) {
current->hangup();
if (const auto still = currentGroupCall()) {
destroyGroupCall(still);
}
}
}
bool Instance::activateCurrentCall() {
if (inCall()) {
_currentCallPanel->showAndActivate();

View File

@ -40,10 +40,7 @@ public:
~Instance();
void startOutgoingCall(not_null<UserData*> user, bool video);
void startGroupCall(not_null<ChannelData*> channel);
void joinGroupCall(
not_null<ChannelData*> channel,
const MTPInputGroupCall &call);
void startOrJoinGroupCall(not_null<ChannelData*> channel);
void handleUpdate(
not_null<Main::Session*> session,
const MTPUpdate &update);
@ -53,6 +50,9 @@ public:
[[nodiscard]] rpl::producer<Call*> currentCallValue() const;
[[nodiscard]] GroupCall *currentGroupCall() const;
[[nodiscard]] rpl::producer<GroupCall*> currentGroupCallValue() const;
[[nodiscard]] bool inCall() const;
[[nodiscard]] bool inGroupCall() const;
bool activateCurrentCall();
std::shared_ptr<tgcalls::VideoCaptureInterface> getVideoCapture() override;
void setCurrentAudioDevice(bool input, const QString &deviceId);
@ -98,9 +98,7 @@ private:
void refreshServerConfig(not_null<Main::Session*> session);
bytes::const_span updateDhConfig(const MTPmessages_DhConfig &data);
bool activateCurrentCall();
[[nodiscard]] bool inCall() const;
[[nodiscard]] bool inGroupCall() const;
void destroyCurrentCall();
void handleCallUpdate(
not_null<Main::Session*> session,
const MTPPhoneCall &call);

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "lang/lang_keys.h"
#include "mainwidget.h"
#include "main/main_session.h"
#include "main/main_domain.h" // Core::App().domain().activate().
#include "apiwrap.h"
#include "layout.h"
#include "history/history.h"
@ -75,6 +76,24 @@ constexpr auto kPinnedMessageTextLimit = 16;
});
}
[[nodiscard]] ClickHandlerPtr ChannelCallClickHandler(
not_null<ChannelData*> megagroup,
uint64 callId) {
return std::make_shared<LambdaClickHandler>([=] {
const auto call = megagroup->call();
if (call && call->id() == callId) {
const auto &windows = megagroup->session().windows();
if (windows.empty()) {
Core::App().domain().activate(&megagroup->session().account());
if (windows.empty()) {
return;
}
}
windows.front()->startOrJoinGroupCall(megagroup);
}
});
}
} // namespace
void HistoryService::setMessageByAction(const MTPmessageAction &action) {
@ -518,12 +537,7 @@ HistoryService::PreparedText HistoryService::prepareStartedCallText(
const auto channel = history()->peer->asChannel();
auto chatText = tr::lng_action_group_call_started_chat(tr::now);
if (channel && linkCallId) {
result.links.push_back(std::make_shared<LambdaClickHandler>([=] {
const auto call = channel->call();
if (call && call->id() == linkCallId) {
Core::App().calls().joinGroupCall(channel, call->input());
}
}));
result.links.push_back(ChannelCallClickHandler(channel, linkCallId));
chatText = textcmdLink(2, chatText);
}
result.text = tr::lng_action_group_call_started(
@ -545,12 +559,7 @@ HistoryService::PreparedText HistoryService::prepareInvitedToCallText(
result.links.push_back(fromLink());
auto linkIndex = 1;
if (channel && linkCallId) {
result.links.push_back(std::make_shared<LambdaClickHandler>([=] {
const auto call = channel->call();
if (call && call->id() == linkCallId) {
Core::App().calls().joinGroupCall(channel, call->input());
}
}));
result.links.push_back(ChannelCallClickHandler(channel, linkCallId));
chatText = textcmdLink(++linkIndex, chatText);
}
if (users.size() == 1) {

View File

@ -5441,8 +5441,8 @@ void HistoryWidget::setupGroupCallTracker() {
.text = tr::lng_group_call_no_anonymous(tr::now),
});
return;
} else if (const auto call = channel->call()) {
Core::App().calls().joinGroupCall(channel, call->input());
} else if (channel->call()) {
controller()->startOrJoinGroupCall(channel);
}
}, _groupCallBar->lifetime());

View File

@ -221,18 +221,10 @@ void TopBarWidget::call() {
void TopBarWidget::groupCall() {
if (const auto peer = _activeChat.key.peer()) {
if (const auto megagroup = peer->asMegagroup()) {
if (megagroup->amAnonymous()) {
Ui::ShowMultilineToast({
.text = tr::lng_group_call_no_anonymous(tr::now),
});
} else if (const auto call = megagroup->call()) {
Core::App().calls().joinGroupCall(megagroup, call->input());
} else {
Core::App().calls().startGroupCall(megagroup);
}
_controller->startOrJoinGroupCall(megagroup);
} else if (const auto chat = peer->asChat()) {
const auto start = [=](not_null<ChannelData*> megagroup) {
Core::App().calls().startGroupCall(megagroup);
_controller->startOrJoinGroupCall(megagroup);
};
peer->session().api().migrateChat(chat, crl::guard(this, start));
}

View File

@ -97,6 +97,7 @@ private:
void call();
void groupCall();
void startGroupCall(not_null<ChannelData*> megagroup, bool confirmed);
void search();
void showMenu();
void toggleInfoSection();

View File

@ -38,6 +38,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_utilities.h"
#include "ui/delayed_activation.h"
#include "ui/toast/toast.h"
#include "ui/toasts/common_toasts.h"
#include "calls/calls_instance.h" // Core::App().calls().inCall().
#include "boxes/calendar_box.h"
#include "boxes/confirm_box.h"
#include "mainwidget.h"
@ -930,6 +932,40 @@ void SessionController::closeThirdSection() {
}
}
void SessionController::startOrJoinGroupCall(
not_null<ChannelData*> megagroup,
bool confirmedLeaveOther) {
if (megagroup->amAnonymous()) {
Ui::ShowMultilineToast({
.text = tr::lng_group_call_no_anonymous(tr::now),
});
return;
}
auto &calls = Core::App().calls();
const auto confirm = [&](QString text, QString button) {
Ui::show(Box<ConfirmBox>(text, button, crl::guard(this, [=] {
Ui::hideLayer();
startOrJoinGroupCall(megagroup, true);
})));
};
if (!confirmedLeaveOther && calls.inCall()) {
// Do you want to leave your active voice chat to join a voice chat in this group?
confirm(
tr::lng_call_leave_to_other_sure(tr::now),
tr::lng_call_bar_hangup(tr::now));
} else if (!confirmedLeaveOther && calls.inGroupCall()) {
if (calls.currentGroupCall()->channel() == megagroup) {
calls.activateCurrentCall();
} else {
confirm(
tr::lng_group_call_leave_to_other_sure(tr::now),
tr::lng_group_call_leave(tr::now));
}
} else {
calls.startOrJoinGroupCall(megagroup);
}
}
void SessionController::showJumpToDate(Dialogs::Key chat, QDate requestedDate) {
const auto currentPeerDate = [&] {
if (const auto history = chat.history()) {

View File

@ -296,6 +296,10 @@ public:
void resizeForThirdSection();
void closeThirdSection();
void startOrJoinGroupCall(
not_null<ChannelData*> megagroup,
bool confirmedLeaveOther = false);
void showSection(
SectionMemento &&memento,
const SectionShow &params = SectionShow()) override;