mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Make 'voice chat' links clickable in service messages.
This commit is contained in:
parent
a61567e1a8
commit
33fc3fe354
3 changed files with 185 additions and 50 deletions
|
@ -1062,11 +1062,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_duration_minsec_seconds#other" = "{count} sec";
|
"lng_duration_minsec_seconds#other" = "{count} sec";
|
||||||
"lng_duration_minutes_seconds" = "{minutes_count} {seconds_count}";
|
"lng_duration_minutes_seconds" = "{minutes_count} {seconds_count}";
|
||||||
|
|
||||||
"lng_action_invite_user" = "{from} invited {user} to the voice chat";
|
"lng_action_invite_user" = "{from} invited {user} to {chat}";
|
||||||
"lng_action_invite_users_many" = "{from} invited {users} to the voice 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_one" = "{accumulated}, {user}";
|
||||||
"lng_action_invite_users_and_last" = "{accumulated} and {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_group_call_finished" = "Voice chat finished ({duration})";
|
||||||
"lng_action_add_user" = "{from} added {user}";
|
"lng_action_add_user" = "{from} added {user}";
|
||||||
"lng_action_add_users_many" = "{from} added {users}";
|
"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_body" = "To add more members, you can upgrade your group to a supergroup.";
|
||||||
"lng_profile_migrate_learn_more" = "Learn more »";
|
"lng_profile_migrate_learn_more" = "Learn more »";
|
||||||
"lng_profile_migrate_button" = "Upgrade to supergroup";
|
"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_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.";
|
"lng_channel_not_accessible" = "Sorry, this channel is not accessible.";
|
||||||
|
|
|
@ -24,7 +24,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
#include "data/data_group_call.h" // Data::GroupCall::id().
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
|
#include "calls/calls_instance.h" // Core::App().calls().joinGroupCall.
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "storage/storage_shared_media.h"
|
#include "storage/storage_shared_media.h"
|
||||||
|
@ -35,6 +37,44 @@ namespace {
|
||||||
|
|
||||||
constexpr auto kPinnedMessageTextLimit = 16;
|
constexpr auto kPinnedMessageTextLimit = 16;
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<bool> ChannelHasThisCallValue(
|
||||||
|
not_null<ChannelData*> 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<bool> ChannelHasThisCall(
|
||||||
|
not_null<ChannelData*> 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
|
} // namespace
|
||||||
|
|
||||||
void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||||
|
@ -278,53 +318,32 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||||
if (const auto duration = action.vduration()) {
|
if (const auto duration = action.vduration()) {
|
||||||
return prepareDiscardedCallText(duration->v);
|
return prepareDiscardedCallText(duration->v);
|
||||||
}
|
}
|
||||||
auto result = PreparedText{};
|
const auto callId = CallIdFromInput(action.vcall());
|
||||||
result.links.push_back(fromLink());
|
const auto channel = history()->peer->asChannel();
|
||||||
result.text = tr::lng_action_group_call_started(tr::now, lt_from, fromLinkText());
|
const auto linkCallId = !channel
|
||||||
return result;
|
? 0
|
||||||
|
: ChannelHasThisCall(channel, callId).value_or(false)
|
||||||
|
? callId
|
||||||
|
: 0;
|
||||||
|
return prepareStartedCallText(linkCallId);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto prepareInviteToGroupCall = [this](const MTPDmessageActionInviteToGroupCall &action) {
|
auto prepareInviteToGroupCall = [this](const MTPDmessageActionInviteToGroupCall &action) {
|
||||||
const auto channel = history()->peer->asChannel();
|
const auto callId = CallIdFromInput(action.vcall());
|
||||||
const auto callId = action.vcall().match([&](const MTPDinputGroupCall &data) {
|
|
||||||
return data.vid().v;
|
|
||||||
});
|
|
||||||
const auto owner = &history()->owner();
|
const auto owner = &history()->owner();
|
||||||
const auto registerUser = [&](UserId userId) {
|
const auto channel = history()->peer->asChannel();
|
||||||
const auto user = owner->user(userId);
|
for (const auto id : action.vusers().v) {
|
||||||
|
const auto user = owner->user(id.v);
|
||||||
if (channel && callId) {
|
if (channel && callId) {
|
||||||
owner->registerInvitedToCallUser(callId, channel, user);
|
owner->registerInvitedToCallUser(callId, channel, user);
|
||||||
}
|
}
|
||||||
return user;
|
|
||||||
};
|
};
|
||||||
auto result = PreparedText{};
|
const auto linkCallId = !channel
|
||||||
auto &users = action.vusers().v;
|
? 0
|
||||||
if (users.size() == 1) {
|
: ChannelHasThisCall(channel, callId).value_or(false)
|
||||||
auto user = registerUser(users[0].v);
|
? callId
|
||||||
result.links.push_back(fromLink());
|
: 0;
|
||||||
result.links.push_back(user->createOpenLink());
|
return prepareInvitedToCallText(action.vusers().v, linkCallId);
|
||||||
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 messageText = action.match([&](
|
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) };
|
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<LambdaClickHandler>([=] {
|
||||||
|
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<MTPint> &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<LambdaClickHandler>([=] {
|
||||||
|
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() {
|
HistoryService::PreparedText HistoryService::preparePinnedText() {
|
||||||
auto result = PreparedText {};
|
auto result = PreparedText {};
|
||||||
auto pinned = Get<HistoryServicePinned>();
|
auto pinned = Get<HistoryServicePinned>();
|
||||||
|
@ -831,8 +917,9 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) {
|
||||||
} else {
|
} else {
|
||||||
UpdateComponents(HistoryServiceOngoingCall::Bit());
|
UpdateComponents(HistoryServiceOngoingCall::Bit());
|
||||||
const auto call = Get<HistoryServiceOngoingCall>();
|
const auto call = Get<HistoryServiceOngoingCall>();
|
||||||
const auto id = data.vcall().c_inputGroupCall().vid().v;
|
const auto id = CallIdFromInput(data.vcall());
|
||||||
call->lifetime.destroy();
|
call->lifetime.destroy();
|
||||||
|
|
||||||
history()->owner().groupCallDiscards(
|
history()->owner().groupCallDiscards(
|
||||||
) | rpl::filter([=](Data::Session::GroupCallDiscard discard) {
|
) | rpl::filter([=](Data::Session::GroupCallDiscard discard) {
|
||||||
return (discard.id == id);
|
return (discard.id == id);
|
||||||
|
@ -841,6 +928,55 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) {
|
||||||
RemoveComponents(HistoryServiceOngoingCall::Bit());
|
RemoveComponents(HistoryServiceOngoingCall::Bit());
|
||||||
updateText(prepareDiscardedCallText(discard.duration));
|
updateText(prepareDiscardedCallText(discard.duration));
|
||||||
}, call->lifetime);
|
}, 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<bool>();
|
||||||
|
if (!hasLink) {
|
||||||
|
RemoveComponents(HistoryServiceOngoingCall::Bit());
|
||||||
|
} else {
|
||||||
|
UpdateComponents(HistoryServiceOngoingCall::Bit());
|
||||||
|
const auto call = Get<HistoryServiceOngoingCall>();
|
||||||
|
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()) {
|
if (const auto replyTo = message.vreply_to()) {
|
||||||
|
|
|
@ -157,6 +157,10 @@ private:
|
||||||
PreparedText prepareGameScoreText();
|
PreparedText prepareGameScoreText();
|
||||||
PreparedText preparePaymentSentText();
|
PreparedText preparePaymentSentText();
|
||||||
PreparedText prepareDiscardedCallText(int duration);
|
PreparedText prepareDiscardedCallText(int duration);
|
||||||
|
PreparedText prepareStartedCallText(uint64 linkCallId);
|
||||||
|
PreparedText prepareInvitedToCallText(
|
||||||
|
const QVector<MTPint> &users,
|
||||||
|
uint64 linkCallId);
|
||||||
|
|
||||||
friend class HistoryView::Service;
|
friend class HistoryView::Service;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue