From 546881c72037e52044835bcfe4d3256054ee44a2 Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 8 Dec 2020 19:09:13 +0400 Subject: [PATCH] Join other calls with confirmation. --- Telegram/Resources/langs/lang.strings | 2 + Telegram/SourceFiles/calls/calls_call.cpp | 15 ++++--- .../SourceFiles/calls/calls_group_call.cpp | 15 ++++--- Telegram/SourceFiles/calls/calls_instance.cpp | 43 +++++++++++-------- Telegram/SourceFiles/calls/calls_instance.h | 12 +++--- .../SourceFiles/history/history_service.cpp | 33 ++++++++------ .../SourceFiles/history/history_widget.cpp | 4 +- .../view/history_view_top_bar_widget.cpp | 12 +----- .../view/history_view_top_bar_widget.h | 1 + .../window/window_session_controller.cpp | 36 ++++++++++++++++ .../window/window_session_controller.h | 4 ++ 11 files changed, 119 insertions(+), 58 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 896824f54..a935525e0 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -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"; diff --git a/Telegram/SourceFiles/calls/calls_call.cpp b/Telegram/SourceFiles/calls/calls_call.cpp index 913536660..669d9153c 100644 --- a/Telegram/SourceFiles/calls/calls_call.cpp +++ b/Telegram/SourceFiles/calls/calls_call.cpp @@ -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) { diff --git a/Telegram/SourceFiles/calls/calls_group_call.cpp b/Telegram/SourceFiles/calls/calls_group_call.cpp index 9ba7dccc5..af8541429 100644 --- a/Telegram/SourceFiles/calls/calls_group_call.cpp +++ b/Telegram/SourceFiles/calls/calls_group_call.cpp @@ -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) { diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp index f1c405810..e05bbfc16 100644 --- a/Telegram/SourceFiles/calls/calls_instance.cpp +++ b/Telegram/SourceFiles/calls/calls_instance.cpp @@ -58,23 +58,13 @@ void Instance::startOutgoingCall(not_null user, bool video) { }), video); } -void Instance::startGroupCall(not_null channel) { - if (activateCurrentCall()) { - return; - } +void Instance::startOrJoinGroupCall(not_null channel) { + destroyCurrentCall(); requestPermissionsOrFail(crl::guard(this, [=] { - createGroupCall(channel, MTP_inputGroupCall(MTPlong(), MTPlong())); - }), false); -} - -void Instance::joinGroupCall( - not_null 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(); diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h index 10d9b56b1..0c9458cdc 100644 --- a/Telegram/SourceFiles/calls/calls_instance.h +++ b/Telegram/SourceFiles/calls/calls_instance.h @@ -40,10 +40,7 @@ public: ~Instance(); void startOutgoingCall(not_null user, bool video); - void startGroupCall(not_null channel); - void joinGroupCall( - not_null channel, - const MTPInputGroupCall &call); + void startOrJoinGroupCall(not_null channel); void handleUpdate( not_null session, const MTPUpdate &update); @@ -53,6 +50,9 @@ public: [[nodiscard]] rpl::producer currentCallValue() const; [[nodiscard]] GroupCall *currentGroupCall() const; [[nodiscard]] rpl::producer currentGroupCallValue() const; + [[nodiscard]] bool inCall() const; + [[nodiscard]] bool inGroupCall() const; + bool activateCurrentCall(); std::shared_ptr getVideoCapture() override; void setCurrentAudioDevice(bool input, const QString &deviceId); @@ -98,9 +98,7 @@ private: void refreshServerConfig(not_null 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 session, const MTPPhoneCall &call); diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index d804a75c6..528943345 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -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 megagroup, + uint64 callId) { + return std::make_shared([=] { + 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([=] { - 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([=] { - 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) { diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index feefa41fb..fe5c964c0 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -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()); diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp index a3885c7ea..0741b2e29 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.cpp @@ -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 megagroup) { - Core::App().calls().startGroupCall(megagroup); + _controller->startOrJoinGroupCall(megagroup); }; peer->session().api().migrateChat(chat, crl::guard(this, start)); } diff --git a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h index a79b5dcc2..076c56f0d 100644 --- a/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h +++ b/Telegram/SourceFiles/history/view/history_view_top_bar_widget.h @@ -97,6 +97,7 @@ private: void call(); void groupCall(); + void startGroupCall(not_null megagroup, bool confirmed); void search(); void showMenu(); void toggleInfoSection(); diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 7828489c0..27eb8fc10 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -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 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(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()) { diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 2feaa18ec..065d8e3ec 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -296,6 +296,10 @@ public: void resizeForThirdSection(); void closeThirdSection(); + void startOrJoinGroupCall( + not_null megagroup, + bool confirmedLeaveOther = false); + void showSection( SectionMemento &&memento, const SectionShow ¶ms = SectionShow()) override;