diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 04a47b633..896824f54 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1062,11 +1062,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_duration_minsec_seconds#other" = "{count} sec"; "lng_duration_minutes_seconds" = "{minutes_count} {seconds_count}"; -"lng_action_invite_user" = "{from} invited {user} to the voice chat"; -"lng_action_invite_users_many" = "{from} invited {users} to the voice chat"; +"lng_action_invite_user" = "{from} invited {user} to {chat}"; +"lng_action_invite_users_many" = "{from} invited {users} to {chat}"; +"lng_action_invite_user_chat" = "the voice chat"; "lng_action_invite_users_and_one" = "{accumulated}, {user}"; "lng_action_invite_users_and_last" = "{accumulated} and {user}"; -"lng_action_group_call_started" = "{from} started a voice chat"; +"lng_action_group_call_started" = "{from} started {chat}"; +"lng_action_group_call_started_chat" = "a voice chat"; "lng_action_group_call_finished" = "Voice chat finished ({duration})"; "lng_action_add_user" = "{from} added {user}"; "lng_action_add_users_many" = "{from} added {users}"; @@ -1142,13 +1144,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_profile_migrate_body" = "To add more members, you can upgrade your group to a supergroup."; "lng_profile_migrate_learn_more" = "Learn more »"; "lng_profile_migrate_button" = "Upgrade to supergroup"; -"lng_profile_convert_title" = "Convert to supergroup"; -"lng_profile_convert_feature1" = "— New members see the full message history"; -"lng_profile_convert_feature2" = "— Messages are deleted for all members"; -"lng_profile_convert_feature3" = "— Admins can pin important messages"; -"lng_profile_convert_feature4" = "— Creator can set a public link for the group"; -"lng_profile_convert_warning" = "{bold_start}Note:{bold_end} This action can not be undone"; -"lng_profile_convert_confirm" = "Convert"; "lng_profile_add_more_after_create" = "You will be able to add more members after you create the group."; "lng_channel_not_accessible" = "Sorry, this channel is not accessible."; diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index 7467f196f..d804a75c6 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -24,7 +24,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_channel.h" #include "data/data_user.h" #include "data/data_changes.h" +#include "data/data_group_call.h" // Data::GroupCall::id(). #include "core/application.h" +#include "calls/calls_instance.h" // Core::App().calls().joinGroupCall. #include "window/notifications_manager.h" #include "window/window_session_controller.h" #include "storage/storage_shared_media.h" @@ -35,6 +37,44 @@ namespace { constexpr auto kPinnedMessageTextLimit = 16; +[[nodiscard]] rpl::producer ChannelHasThisCallValue( + not_null channel, + uint64 id) { + return channel->session().changes().peerFlagsValue( + channel, + Data::PeerUpdate::Flag::GroupCall + ) | rpl::filter([=] { + return (channel->call() != nullptr) + || !(channel->flags() + & MTPDchannel::Flag::f_call_active); + }) | rpl::map([=] { + const auto call = channel->call(); + return (call && call->id() == id); + }) | rpl::distinct_until_changed( + ) | rpl::take_while([=](bool hasThisCall) { + return hasThisCall; + }) | rpl::then( + rpl::single(false) + ); +} + +[[nodiscard]] std::optional ChannelHasThisCall( + not_null channel, + uint64 id) { + const auto call = channel->call(); + return call + ? std::make_optional(call->id() == id) + : (channel->flags() & MTPDchannel::Flag::f_call_active) + ? std::nullopt + : std::make_optional(false); +} + +[[nodiscard]] uint64 CallIdFromInput(const MTPInputGroupCall &data) { + return data.match([&](const MTPDinputGroupCall &data) { + return data.vid().v; + }); +} + } // namespace void HistoryService::setMessageByAction(const MTPmessageAction &action) { @@ -278,53 +318,32 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) { if (const auto duration = action.vduration()) { return prepareDiscardedCallText(duration->v); } - auto result = PreparedText{}; - result.links.push_back(fromLink()); - result.text = tr::lng_action_group_call_started(tr::now, lt_from, fromLinkText()); - return result; + const auto callId = CallIdFromInput(action.vcall()); + const auto channel = history()->peer->asChannel(); + const auto linkCallId = !channel + ? 0 + : ChannelHasThisCall(channel, callId).value_or(false) + ? callId + : 0; + return prepareStartedCallText(linkCallId); }; auto prepareInviteToGroupCall = [this](const MTPDmessageActionInviteToGroupCall &action) { - const auto channel = history()->peer->asChannel(); - const auto callId = action.vcall().match([&](const MTPDinputGroupCall &data) { - return data.vid().v; - }); + const auto callId = CallIdFromInput(action.vcall()); const auto owner = &history()->owner(); - const auto registerUser = [&](UserId userId) { - const auto user = owner->user(userId); + const auto channel = history()->peer->asChannel(); + for (const auto id : action.vusers().v) { + const auto user = owner->user(id.v); if (channel && callId) { owner->registerInvitedToCallUser(callId, channel, user); } - return user; }; - auto result = PreparedText{}; - auto &users = action.vusers().v; - if (users.size() == 1) { - auto user = registerUser(users[0].v); - result.links.push_back(fromLink()); - result.links.push_back(user->createOpenLink()); - result.text = tr::lng_action_invite_user(tr::now, lt_from, fromLinkText(), lt_user, textcmdLink(2, user->name)); - } else if (users.isEmpty()) { - result.links.push_back(fromLink()); - result.text = tr::lng_action_invite_user(tr::now, lt_from, fromLinkText(), lt_user, qsl("somebody")); - } else { - result.links.push_back(fromLink()); - for (auto i = 0, l = users.size(); i != l; ++i) { - auto user = registerUser(users[i].v); - result.links.push_back(user->createOpenLink()); - - auto linkText = textcmdLink(i + 2, user->name); - if (i == 0) { - result.text = linkText; - } else if (i + 1 == l) { - result.text = tr::lng_action_invite_users_and_last(tr::now, lt_accumulated, result.text, lt_user, linkText); - } else { - result.text = tr::lng_action_invite_users_and_one(tr::now, lt_accumulated, result.text, lt_user, linkText); - } - } - result.text = tr::lng_action_invite_users_many(tr::now, lt_from, fromLinkText(), lt_users, result.text); - } - return result; + const auto linkCallId = !channel + ? 0 + : ChannelHasThisCall(channel, callId).value_or(false) + ? callId + : 0; + return prepareInvitedToCallText(action.vusers().v, linkCallId); }; const auto messageText = action.match([&]( @@ -492,6 +511,73 @@ HistoryService::PreparedText HistoryService::prepareDiscardedCallText( return PreparedText{ tr::lng_action_group_call_finished(tr::now, lt_duration, text) }; } +HistoryService::PreparedText HistoryService::prepareStartedCallText( + uint64 linkCallId) { + auto result = PreparedText{}; + result.links.push_back(fromLink()); + 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()); + } + })); + chatText = textcmdLink(2, chatText); + } + result.text = tr::lng_action_group_call_started( + tr::now, + lt_from, + fromLinkText(), + lt_chat, + chatText); + return result; +} + +HistoryService::PreparedText HistoryService::prepareInvitedToCallText( + const QVector &users, + uint64 linkCallId) { + const auto channel = history()->peer->asChannel(); + const auto owner = &channel->owner(); + auto chatText = tr::lng_action_invite_user_chat(tr::now); + auto result = PreparedText{}; + 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()); + } + })); + chatText = textcmdLink(++linkIndex, chatText); + } + if (users.size() == 1) { + auto user = owner->user(users[0].v); + result.links.push_back(user->createOpenLink()); + result.text = tr::lng_action_invite_user(tr::now, lt_from, fromLinkText(), lt_user, textcmdLink(++linkIndex, user->name), lt_chat, chatText); + } else if (users.isEmpty()) { + result.text = tr::lng_action_invite_user(tr::now, lt_from, fromLinkText(), lt_user, qsl("somebody"), lt_chat, chatText); + } else { + for (auto i = 0, l = users.size(); i != l; ++i) { + auto user = owner->user(users[i].v); + result.links.push_back(user->createOpenLink()); + + auto linkText = textcmdLink(++linkIndex, user->name); + if (i == 0) { + result.text = linkText; + } else if (i + 1 == l) { + result.text = tr::lng_action_invite_users_and_last(tr::now, lt_accumulated, result.text, lt_user, linkText); + } else { + result.text = tr::lng_action_invite_users_and_one(tr::now, lt_accumulated, result.text, lt_user, linkText); + } + } + result.text = tr::lng_action_invite_users_many(tr::now, lt_from, fromLinkText(), lt_users, result.text, lt_chat, chatText); + } + return result; +} + HistoryService::PreparedText HistoryService::preparePinnedText() { auto result = PreparedText {}; auto pinned = Get(); @@ -831,8 +917,9 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) { } else { UpdateComponents(HistoryServiceOngoingCall::Bit()); const auto call = Get(); - const auto id = data.vcall().c_inputGroupCall().vid().v; + const auto id = CallIdFromInput(data.vcall()); call->lifetime.destroy(); + history()->owner().groupCallDiscards( ) | rpl::filter([=](Data::Session::GroupCallDiscard discard) { return (discard.id == id); @@ -841,6 +928,55 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) { RemoveComponents(HistoryServiceOngoingCall::Bit()); updateText(prepareDiscardedCallText(discard.duration)); }, call->lifetime); + + if (const auto channel = history()->peer->asChannel()) { + const auto has = ChannelHasThisCall(channel, id); + if (!has.has_value()) { + ChannelHasThisCallValue( + channel, + id + ) | rpl::start_with_next([=](bool has) { + updateText(prepareStartedCallText(has ? id : 0)); + }, call->lifetime); + } else if (*has) { + ChannelHasThisCallValue( + channel, + id + ) | rpl::skip(1) | rpl::start_with_next([=](bool has) { + Assert(!has); + updateText(prepareStartedCallText(0)); + }, call->lifetime); + } + } + } + } else if (message.vaction().type() == mtpc_messageActionInviteToGroupCall) { + const auto &data = message.vaction().c_messageActionInviteToGroupCall(); + const auto id = CallIdFromInput(data.vcall()); + const auto channel = history()->peer->asChannel(); + const auto has = channel + ? ChannelHasThisCall(channel, id) + : std::make_optional(false); + auto hasLink = !has.has_value() + ? ChannelHasThisCallValue(channel, id) + : (*has) + ? ChannelHasThisCallValue( + channel, + id) | rpl::skip(1) | rpl::type_erased() + : rpl::producer(); + if (!hasLink) { + RemoveComponents(HistoryServiceOngoingCall::Bit()); + } else { + UpdateComponents(HistoryServiceOngoingCall::Bit()); + const auto call = Get(); + call->lifetime.destroy(); + + const auto users = data.vusers().v; + std::move(hasLink) | rpl::start_with_next([=](bool has) { + updateText(prepareInvitedToCallText(users, has ? id : 0)); + if (!has) { + RemoveComponents(HistoryServiceOngoingCall::Bit()); + } + }, call->lifetime); } } if (const auto replyTo = message.vreply_to()) { diff --git a/Telegram/SourceFiles/history/history_service.h b/Telegram/SourceFiles/history/history_service.h index f9f93240a..7b7bcbab3 100644 --- a/Telegram/SourceFiles/history/history_service.h +++ b/Telegram/SourceFiles/history/history_service.h @@ -157,6 +157,10 @@ private: PreparedText prepareGameScoreText(); PreparedText preparePaymentSentText(); PreparedText prepareDiscardedCallText(int duration); + PreparedText prepareStartedCallText(uint64 linkCallId); + PreparedText prepareInvitedToCallText( + const QVector &users, + uint64 linkCallId); friend class HistoryView::Service;