mirror of https://github.com/procxx/kepka.git
Add phrases and layout for all events in log.
This commit is contained in:
parent
fee8690ca6
commit
4962fdf5ae
|
@ -1351,6 +1351,27 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
"lng_admin_log_deleted_message" = "{from} deleted message:";
|
"lng_admin_log_deleted_message" = "{from} deleted message:";
|
||||||
"lng_admin_log_participant_joined" = "{from} joined the group";
|
"lng_admin_log_participant_joined" = "{from} joined the group";
|
||||||
"lng_admin_log_participant_left" = "{from} left the group";
|
"lng_admin_log_participant_left" = "{from} left the group";
|
||||||
|
"lng_admin_log_invited" = "invited {user}";
|
||||||
|
"lng_admin_log_banned" = "banned {user}";
|
||||||
|
"lng_admin_log_restricted" = "changed restrictions for {user} {until}";
|
||||||
|
"lng_admin_log_promoted" = "changed privileges for {user}";
|
||||||
|
"lng_admin_log_user_with_username" = "{name} ({mention})";
|
||||||
|
"lng_admin_log_restricted_forever" = "indefinitely";
|
||||||
|
"lng_admin_log_restricted_until" = "until {date}";
|
||||||
|
"lng_admin_log_banned_view_messages" = "Read messages";
|
||||||
|
"lng_admin_log_banned_send_messages" = "Send messages";
|
||||||
|
"lng_admin_log_banned_send_media" = "Send media";
|
||||||
|
"lng_admin_log_banned_send_stickers" = "Send stickers & GIFs";
|
||||||
|
"lng_admin_log_banned_embed_links" = "Embed links";
|
||||||
|
"lng_admin_log_admin_change_info" = "Change info";
|
||||||
|
"lng_admin_log_admin_post_messages" = "Post messages";
|
||||||
|
"lng_admin_log_admin_edit_messages" = "Edit messages";
|
||||||
|
"lng_admin_log_admin_delete_messages" = "Delete messages";
|
||||||
|
"lng_admin_log_admin_ban_users" = "Ban users";
|
||||||
|
"lng_admin_log_admin_invite_users" = "Add users";
|
||||||
|
"lng_admin_log_admin_invite_link" = "Invite users via link";
|
||||||
|
"lng_admin_log_admin_pin_messages" = "Pin messages";
|
||||||
|
"lng_admin_log_admin_add_admins" = "Add new admins";
|
||||||
|
|
||||||
// Not used
|
// Not used
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,6 @@ public:
|
||||||
EditRestrictedBox(QWidget*, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user, bool hasAdminRights, const MTPChannelBannedRights &rights, base::lambda<void(MTPChannelBannedRights)> callback);
|
EditRestrictedBox(QWidget*, gsl::not_null<ChannelData*> channel, gsl::not_null<UserData*> user, bool hasAdminRights, const MTPChannelBannedRights &rights, base::lambda<void(MTPChannelBannedRights)> callback);
|
||||||
|
|
||||||
static MTPChannelBannedRights DefaultRights(gsl::not_null<ChannelData*> channel);
|
static MTPChannelBannedRights DefaultRights(gsl::not_null<ChannelData*> channel);
|
||||||
static constexpr auto kRestrictUntilForever = TimeId(INT_MAX);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void prepare() override;
|
void prepare() override;
|
||||||
|
@ -109,7 +108,7 @@ private:
|
||||||
void showRestrictUntil();
|
void showRestrictUntil();
|
||||||
void setRestrictUntil(int32 until);
|
void setRestrictUntil(int32 until);
|
||||||
bool isUntilForever() {
|
bool isUntilForever() {
|
||||||
return (_until <= 0) || (_until == kRestrictUntilForever);
|
return ChannelData::IsRestrictedForever(_until);
|
||||||
}
|
}
|
||||||
|
|
||||||
MTPChannelBannedRights _rights;
|
MTPChannelBannedRights _rights;
|
||||||
|
|
|
@ -142,24 +142,35 @@ QString lang(LangKey key);\n\
|
||||||
for (auto &entry : langpack_.entries) {
|
for (auto &entry : langpack_.entries) {
|
||||||
auto isPlural = !entry.keyBase.isEmpty();
|
auto isPlural = !entry.keyBase.isEmpty();
|
||||||
auto &key = entry.key;
|
auto &key = entry.key;
|
||||||
|
auto genericParams = QStringList();
|
||||||
auto params = QStringList();
|
auto params = QStringList();
|
||||||
auto applyTags = QStringList();
|
auto applyTags = QStringList();
|
||||||
|
auto plural = QString();
|
||||||
|
auto nonPluralTagFound = false;
|
||||||
for (auto &tagData : entry.tags) {
|
for (auto &tagData : entry.tags) {
|
||||||
auto &tag = tagData.tag;
|
auto &tag = tagData.tag;
|
||||||
auto isPluralTag = isPlural && (tag == kPluralTag);
|
auto isPluralTag = isPlural && (tag == kPluralTag);
|
||||||
|
genericParams.push_back("lngtag_" + tag + ", " + (isPluralTag ? "float64 " : "const ResultString &") + tag + "__val");
|
||||||
params.push_back("lngtag_" + tag + ", " + (isPluralTag ? "float64 " : "const QString &") + tag + "__val");
|
params.push_back("lngtag_" + tag + ", " + (isPluralTag ? "float64 " : "const QString &") + tag + "__val");
|
||||||
if (!isPluralTag) {
|
if (isPluralTag) {
|
||||||
applyTags.push_back("\tresult = Lang::Tag(result, lt_" + tag + ", " + tag + "__val);\n");
|
plural = "\tauto plural = Lang::Plural(" + key + ", " + kPluralTag + "__val);\n";
|
||||||
|
applyTags.push_back("\tresult = Lang::ReplaceTag<ResultString>::Call(std::move(result), lt_" + tag + ", Lang::StartReplacements<ResultString>::Call(std::move(plural.replacement)));\n");
|
||||||
|
} else {
|
||||||
|
nonPluralTagFound = true;
|
||||||
|
applyTags.push_back("\tresult = Lang::ReplaceTag<ResultString>::Call(std::move(result), lt_" + tag + ", " + tag + "__val);\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!entry.tags.empty() && (!isPlural || key == ComputePluralKey(entry.keyBase, 0))) {
|
if (!entry.tags.empty() && (!isPlural || key == ComputePluralKey(entry.keyBase, 0))) {
|
||||||
auto initialString = isPlural ? ("Lang::Plural(" + key + ", lt_" + kPluralTag + ", " + kPluralTag + "__val)") : ("lang(" + getFullKey(entry) + ")");
|
auto initialString = isPlural ? ("std::move(plural.string)") : ("lang(" + getFullKey(entry) + ")");
|
||||||
header_->stream() << "\
|
header_->stream() << "\
|
||||||
inline QString " << (isPlural ? entry.keyBase : key) << "(" << params.join(QString(", ")) << ") {\n\
|
template <typename ResultString>\n\
|
||||||
auto result = " << initialString << ";\n\
|
inline ResultString " << (isPlural ? entry.keyBase : key) << "__generic(" << genericParams.join(QString(", ")) << ") {\n\
|
||||||
|
" << plural << "\
|
||||||
|
auto result = Lang::StartReplacements<ResultString>::Call(" << initialString << ");\n\
|
||||||
" << applyTags.join(QString()) << "\
|
" << applyTags.join(QString()) << "\
|
||||||
return result;\n\
|
return result;\n\
|
||||||
}\n\
|
}\n\
|
||||||
|
constexpr auto " << (isPlural ? entry.keyBase : key) << " = &" << (isPlural ? entry.keyBase : key) << "__generic<QString>;\n\
|
||||||
\n";
|
\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,19 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
namespace AdminLog {
|
namespace AdminLog {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
TextWithEntities PrepareText(const QString &value, const QString &emptyValue) {
|
||||||
|
auto result = TextWithEntities { textClean(value) };
|
||||||
|
if (result.text.isEmpty()) {
|
||||||
|
result.text = emptyValue;
|
||||||
|
if (!emptyValue.isEmpty()) {
|
||||||
|
result.entities.push_back(EntityInText(EntityInTextItalic, 0, emptyValue.size()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
textParseEntities(result.text, TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands, &result.entities);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
MTPMessage PrepareLogMessage(const MTPMessage &message, MsgId newId, int32 newDate) {
|
MTPMessage PrepareLogMessage(const MTPMessage &message, MsgId newId, int32 newDate) {
|
||||||
switch (message.type()) {
|
switch (message.type()) {
|
||||||
case mtpc_messageEmpty: return MTP_messageEmpty(MTP_int(newId));
|
case mtpc_messageEmpty: return MTP_messageEmpty(MTP_int(newId));
|
||||||
|
@ -43,7 +56,7 @@ MTPMessage PrepareLogMessage(const MTPMessage &message, MsgId newId, int32 newDa
|
||||||
Unexpected("Type in PrepareLogMessage()");
|
Unexpected("Type in PrepareLogMessage()");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageHasCaption(const MTPMessage &message) {
|
bool MediaCanHaveCaption(const MTPMessage &message) {
|
||||||
if (message.type() != mtpc_message) {
|
if (message.type() != mtpc_message) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -52,6 +65,172 @@ bool MessageHasCaption(const MTPMessage &message) {
|
||||||
return (mediaType == mtpc_messageMediaDocument || mediaType == mtpc_messageMediaPhoto);
|
return (mediaType == mtpc_messageMediaDocument || mediaType == mtpc_messageMediaPhoto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextWithEntities ExtractEditedText(const MTPMessage &message) {
|
||||||
|
if (message.type() != mtpc_message) {
|
||||||
|
return TextWithEntities();
|
||||||
|
}
|
||||||
|
auto &data = message.c_message();
|
||||||
|
auto mediaType = data.has_media() ? data.vmedia.type() : mtpc_messageMediaEmpty;
|
||||||
|
if (mediaType == mtpc_messageMediaDocument) {
|
||||||
|
return PrepareText(qs(data.vmedia.c_messageMediaDocument().vcaption), QString());
|
||||||
|
} else if (mediaType == mtpc_messageMediaPhoto) {
|
||||||
|
return PrepareText(qs(data.vmedia.c_messageMediaPhoto().vcaption), QString());
|
||||||
|
}
|
||||||
|
auto text = textClean(qs(data.vmessage));
|
||||||
|
auto entities = data.has_entities() ? entitiesFromMTP(data.ventities.v) : EntitiesInText();
|
||||||
|
return { text, entities };
|
||||||
|
}
|
||||||
|
|
||||||
|
PhotoData *GenerateChatPhoto(ChannelId channelId, uint64 logEntryId, MTPint date, const MTPDchatPhoto &photo) {
|
||||||
|
// We try to make a unique photoId that will stay the same for each pair (channelId, logEntryId).
|
||||||
|
static const auto RandomIdPart = rand_value<uint64>();
|
||||||
|
auto mixinIdPart = (static_cast<uint64>(static_cast<uint32>(channelId)) << 32) ^ logEntryId;
|
||||||
|
auto photoId = RandomIdPart ^ mixinIdPart;
|
||||||
|
|
||||||
|
auto photoSizes = QVector<MTPPhotoSize>();
|
||||||
|
photoSizes.reserve(2);
|
||||||
|
photoSizes.push_back(MTP_photoSize(MTP_string("a"), photo.vphoto_small, MTP_int(160), MTP_int(160), MTP_int(0)));
|
||||||
|
photoSizes.push_back(MTP_photoSize(MTP_string("c"), photo.vphoto_big, MTP_int(640), MTP_int(640), MTP_int(0)));
|
||||||
|
return App::feedPhoto(MTP_photo(MTP_flags(0), MTP_long(photoId), MTP_long(0), date, MTP_vector<MTPPhotoSize>(photoSizes)));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto CollectChanges = [](auto &phraseMap, auto plusFlags, auto minusFlags) {
|
||||||
|
auto withPrefix = [&phraseMap](auto flags, QChar prefix) {
|
||||||
|
auto result = QString();
|
||||||
|
for (auto &phrase : phraseMap) {
|
||||||
|
if (flags & phrase.first) {
|
||||||
|
result.append('\n' + (prefix + lang(phrase.second)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
const auto kMinus = QChar(0x2212);
|
||||||
|
return withPrefix(plusFlags & ~minusFlags, '+') + withPrefix(minusFlags & ~plusFlags, kMinus);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto GenerateAdminChangeText(gsl::not_null<ChannelData*> channel, const TextWithEntities &user, const MTPChannelAdminRights *newRights, const MTPChannelAdminRights *prevRights) {
|
||||||
|
using Flag = MTPDchannelAdminRights::Flag;
|
||||||
|
using Flags = MTPDchannelAdminRights::Flags;
|
||||||
|
|
||||||
|
Expects(!newRights || newRights->type() == mtpc_channelAdminRights);
|
||||||
|
Expects(!prevRights || prevRights->type() == mtpc_channelAdminRights);
|
||||||
|
auto newFlags = newRights ? newRights->c_channelAdminRights().vflags.v : 0;
|
||||||
|
auto prevFlags = prevRights ? prevRights->c_channelAdminRights().vflags.v : 0;
|
||||||
|
auto result = lng_admin_log_promoted__generic(lt_user, user);
|
||||||
|
|
||||||
|
auto inviteKey = Flag::f_invite_users | Flag::f_invite_link;
|
||||||
|
auto useInviteLinkPhrase = channel->isMegagroup() && channel->anyoneCanAddMembers();
|
||||||
|
auto invitePhrase = (useInviteLinkPhrase ? lng_admin_log_admin_invite_link : lng_admin_log_admin_invite_users);
|
||||||
|
static auto phraseMap = std::map<Flags, LangKey> {
|
||||||
|
{ Flag::f_change_info, lng_admin_log_admin_change_info },
|
||||||
|
{ Flag::f_post_messages, lng_admin_log_admin_post_messages },
|
||||||
|
{ Flag::f_edit_messages, lng_admin_log_admin_edit_messages },
|
||||||
|
{ Flag::f_delete_messages, lng_admin_log_admin_delete_messages },
|
||||||
|
{ Flag::f_ban_users, lng_admin_log_admin_ban_users },
|
||||||
|
{ inviteKey, invitePhrase },
|
||||||
|
{ Flag::f_pin_messages, lng_admin_log_admin_pin_messages },
|
||||||
|
{ Flag::f_add_admins, lng_admin_log_admin_add_admins },
|
||||||
|
};
|
||||||
|
phraseMap[inviteKey] = invitePhrase;
|
||||||
|
|
||||||
|
auto changes = CollectChanges(phraseMap, newFlags, prevFlags);
|
||||||
|
if (!changes.isEmpty()) {
|
||||||
|
result.text.append('\n' + changes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto GenerateBannedChangeText(const TextWithEntities &user, const MTPChannelBannedRights *newRights, const MTPChannelBannedRights *prevRights) {
|
||||||
|
using Flag = MTPDchannelBannedRights::Flag;
|
||||||
|
using Flags = MTPDchannelBannedRights::Flags;
|
||||||
|
|
||||||
|
Expects(!newRights || newRights->type() == mtpc_channelBannedRights);
|
||||||
|
Expects(!prevRights || prevRights->type() == mtpc_channelBannedRights);
|
||||||
|
auto newFlags = newRights ? newRights->c_channelBannedRights().vflags.v : 0;
|
||||||
|
auto prevFlags = prevRights ? prevRights->c_channelBannedRights().vflags.v : 0;
|
||||||
|
auto newUntil = newRights ? newRights->c_channelBannedRights().vuntil_date : MTP_int(0);
|
||||||
|
auto indefinitely = ChannelData::IsRestrictedForever(newUntil.v);
|
||||||
|
if (newFlags & Flag::f_view_messages) {
|
||||||
|
return lng_admin_log_banned__generic(lt_user, user);
|
||||||
|
}
|
||||||
|
auto untilText = indefinitely ? lang(lng_admin_log_restricted_forever) : lng_admin_log_restricted_until(lt_date, langDateTime(::date(newUntil)));
|
||||||
|
auto result = lng_admin_log_restricted__generic(lt_user, user, lt_until, TextWithEntities { untilText });
|
||||||
|
|
||||||
|
static auto phraseMap = std::map<Flags, LangKey> {
|
||||||
|
{ Flag::f_view_messages, lng_admin_log_banned_view_messages },
|
||||||
|
{ Flag::f_send_messages, lng_admin_log_banned_send_messages },
|
||||||
|
{ Flag::f_send_media, lng_admin_log_banned_send_media },
|
||||||
|
{ Flag::f_send_stickers | Flag::f_send_gifs | Flag::f_send_inline | Flag::f_send_games, lng_admin_log_banned_send_stickers },
|
||||||
|
{ Flag::f_embed_links, lng_admin_log_banned_embed_links },
|
||||||
|
};
|
||||||
|
auto changes = CollectChanges(phraseMap, prevFlags, newFlags);
|
||||||
|
if (!changes.isEmpty()) {
|
||||||
|
result.text.append('\n' + changes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto GenerateUserString(MTPint userId) {
|
||||||
|
// User name in "User name (@username)" format with entities.
|
||||||
|
auto user = App::user(userId.v);
|
||||||
|
auto name = TextWithEntities { App::peerName(user) };
|
||||||
|
name.entities.push_back(EntityInText(EntityInTextMentionName, 0, name.text.size(), QString::number(user->id) + '.' + QString::number(user->access)));
|
||||||
|
auto username = user->userName();
|
||||||
|
if (username.isEmpty()) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
auto mention = TextWithEntities { '@' + username };
|
||||||
|
mention.entities.push_back(EntityInText(EntityInTextMention, 0, mention.text.size()));
|
||||||
|
return lng_admin_log_user_with_username__generic(lt_name, name, lt_mention, mention);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GenerateParticipantChangeTextInner(gsl::not_null<ChannelData*> channel, const MTPChannelParticipant &participant, const MTPChannelParticipant *oldParticipant) {
|
||||||
|
auto oldType = oldParticipant ? oldParticipant->type() : 0;
|
||||||
|
|
||||||
|
auto resultForParticipant = [channel, oldParticipant, oldType](auto &&data) {
|
||||||
|
auto user = GenerateUserString(data.vuser_id);
|
||||||
|
if (oldType == mtpc_channelParticipantAdmin) {
|
||||||
|
return GenerateAdminChangeText(channel, user, nullptr, &oldParticipant->c_channelParticipantAdmin().vadmin_rights);
|
||||||
|
} else if (oldType == mtpc_channelParticipantBanned) {
|
||||||
|
return GenerateBannedChangeText(user, nullptr, &oldParticipant->c_channelParticipantBanned().vbanned_rights);
|
||||||
|
}
|
||||||
|
return lng_admin_log_invited__generic(lt_user, user);
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (participant.type()) {
|
||||||
|
case mtpc_channelParticipantCreator: {
|
||||||
|
// No valid string here :(
|
||||||
|
auto &data = participant.c_channelParticipantCreator();
|
||||||
|
return lng_admin_log_invited__generic(lt_user, GenerateUserString(data.vuser_id));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_channelParticipant: return resultForParticipant(participant.c_channelParticipant());
|
||||||
|
case mtpc_channelParticipantSelf: return resultForParticipant(participant.c_channelParticipantSelf());
|
||||||
|
|
||||||
|
case mtpc_channelParticipantAdmin: {
|
||||||
|
auto &data = participant.c_channelParticipantAdmin();
|
||||||
|
auto user = GenerateUserString(data.vuser_id);
|
||||||
|
return GenerateAdminChangeText(channel, user, &data.vadmin_rights, (oldType == mtpc_channelParticipantAdmin) ? &oldParticipant->c_channelParticipantAdmin().vadmin_rights : nullptr);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case mtpc_channelParticipantBanned: {
|
||||||
|
auto &data = participant.c_channelParticipantBanned();
|
||||||
|
auto user = GenerateUserString(data.vuser_id);
|
||||||
|
return GenerateBannedChangeText(user, &data.vbanned_rights, (oldType == mtpc_channelParticipantBanned) ? &oldParticipant->c_channelParticipantBanned().vbanned_rights : nullptr);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unexpected("Participant type in GenerateParticipantChangeTextInner()");
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWithEntities GenerateParticipantChangeText(gsl::not_null<ChannelData*> channel, const MTPChannelParticipant &participant, const MTPChannelParticipant *oldParticipant = nullptr) {
|
||||||
|
auto result = GenerateParticipantChangeTextInner(channel, participant, oldParticipant);
|
||||||
|
result.entities.push_front(EntityInText(EntityInTextItalic, 0, result.text.size()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Item::Item(gsl::not_null<History*> history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event)
|
Item::Item(gsl::not_null<History*> history, LocalIdManager &idManager, const MTPDchannelAdminLogEvent &event)
|
||||||
|
@ -67,10 +246,10 @@ Item::Item(gsl::not_null<History*> history, LocalIdManager &idManager, const MTP
|
||||||
auto fromLink = _from->openLink();
|
auto fromLink = _from->openLink();
|
||||||
auto fromLinkText = textcmdLink(1, fromName);
|
auto fromLinkText = textcmdLink(1, fromName);
|
||||||
|
|
||||||
auto addSimpleServiceMessage = [this, &idManager, date, fromLink](const QString &text) {
|
auto addSimpleServiceMessage = [this, &idManager, date, fromLink](const QString &text, PhotoData *photo = nullptr) {
|
||||||
auto message = HistoryService::PreparedText { text };
|
auto message = HistoryService::PreparedText { text };
|
||||||
message.links.push_back(fromLink);
|
message.links.push_back(fromLink);
|
||||||
addPart(HistoryService::create(_history, idManager.next(), ::date(date), message, 0, peerToUser(_from->id)));
|
addPart(HistoryService::create(_history, idManager.next(), ::date(date), message, 0, peerToUser(_from->id), photo));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto createChangeTitle = [this, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionChangeTitle &action) {
|
auto createChangeTitle = [this, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionChangeTitle &action) {
|
||||||
|
@ -120,9 +299,12 @@ Item::Item(gsl::not_null<History*> history, LocalIdManager &idManager, const MTP
|
||||||
addPart(body);
|
addPart(body);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto createChangePhoto = [this, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionChangePhoto &action) {
|
auto createChangePhoto = [this, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionChangePhoto &action) {
|
||||||
|
t_assert(action.vnew_photo.type() == mtpc_chatPhoto);
|
||||||
|
auto photo = GenerateChatPhoto(channel()->bareId(), _id, date, action.vnew_photo.c_chatPhoto());
|
||||||
|
|
||||||
auto text = (channel()->isMegagroup() ? lng_admin_log_changed_photo_group : lng_admin_log_changed_photo_channel)(lt_from, fromLinkText);
|
auto text = (channel()->isMegagroup() ? lng_admin_log_changed_photo_group : lng_admin_log_changed_photo_channel)(lt_from, fromLinkText);
|
||||||
addSimpleServiceMessage(text);
|
addSimpleServiceMessage(text, photo);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto createToggleInvites = [this, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionToggleInvites &action) {
|
auto createToggleInvites = [this, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionToggleInvites &action) {
|
||||||
|
@ -147,12 +329,22 @@ Item::Item(gsl::not_null<History*> history, LocalIdManager &idManager, const MTP
|
||||||
};
|
};
|
||||||
|
|
||||||
auto createEditMessage = [this, &idManager, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionEditMessage &action) {
|
auto createEditMessage = [this, &idManager, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionEditMessage &action) {
|
||||||
auto text = (MessageHasCaption(action.vnew_message) ? lng_admin_log_edited_caption : lng_admin_log_edited_message)(lt_from, fromLinkText);
|
auto newValue = ExtractEditedText(action.vnew_message);
|
||||||
|
auto canHaveCaption = MediaCanHaveCaption(action.vnew_message);
|
||||||
|
auto text = (canHaveCaption
|
||||||
|
? (newValue.text.isEmpty() ? lng_admin_log_removed_caption : lng_admin_log_edited_caption)
|
||||||
|
: lng_admin_log_edited_message
|
||||||
|
)(lt_from, fromLinkText);
|
||||||
addSimpleServiceMessage(text);
|
addSimpleServiceMessage(text);
|
||||||
|
|
||||||
|
auto oldValue = ExtractEditedText(action.vprev_message);
|
||||||
auto applyServiceAction = false;
|
auto applyServiceAction = false;
|
||||||
auto detachExistingItem = false;
|
auto detachExistingItem = false;
|
||||||
addPart(_history->createItem(PrepareLogMessage(action.vnew_message, idManager.next(), date.v), applyServiceAction, detachExistingItem));
|
auto body = _history->createItem(PrepareLogMessage(action.vnew_message, idManager.next(), date.v), applyServiceAction, detachExistingItem);
|
||||||
|
if (!oldValue.text.isEmpty()) {
|
||||||
|
body->addLogEntryOriginal(lang(canHaveCaption ? lng_admin_log_previous_caption : lng_admin_log_previous_description), oldValue);
|
||||||
|
}
|
||||||
|
addPart(body);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto createDeleteMessage = [this, &idManager, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionDeleteMessage &action) {
|
auto createDeleteMessage = [this, &idManager, date, addSimpleServiceMessage, fromLinkText](const MTPDchannelAdminLogEventActionDeleteMessage &action) {
|
||||||
|
@ -178,21 +370,24 @@ Item::Item(gsl::not_null<History*> history, LocalIdManager &idManager, const MTP
|
||||||
auto bodyFlags = Flag::f_entities | Flag::f_from_id;
|
auto bodyFlags = Flag::f_entities | Flag::f_from_id;
|
||||||
auto bodyReplyTo = 0;
|
auto bodyReplyTo = 0;
|
||||||
auto bodyViaBotId = 0;
|
auto bodyViaBotId = 0;
|
||||||
addPart(HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), { "participant invite text", EntitiesInText() }));
|
auto bodyText = GenerateParticipantChangeText(channel(), action.vparticipant);
|
||||||
|
addPart(HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), bodyText));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto createParticipantToggleBan = [this, &idManager, date](const MTPDchannelAdminLogEventActionParticipantToggleBan &action) {
|
auto createParticipantToggleBan = [this, &idManager, date](const MTPDchannelAdminLogEventActionParticipantToggleBan &action) {
|
||||||
auto bodyFlags = Flag::f_entities | Flag::f_from_id;
|
auto bodyFlags = Flag::f_entities | Flag::f_from_id;
|
||||||
auto bodyReplyTo = 0;
|
auto bodyReplyTo = 0;
|
||||||
auto bodyViaBotId = 0;
|
auto bodyViaBotId = 0;
|
||||||
addPart(HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), { "participant toggle ban text", EntitiesInText() }));
|
auto bodyText = GenerateParticipantChangeText(channel(), action.vnew_participant, &action.vprev_participant);
|
||||||
|
addPart(HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), bodyText));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto createParticipantToggleAdmin = [this, &idManager, date](const MTPDchannelAdminLogEventActionParticipantToggleAdmin &action) {
|
auto createParticipantToggleAdmin = [this, &idManager, date](const MTPDchannelAdminLogEventActionParticipantToggleAdmin &action) {
|
||||||
auto bodyFlags = Flag::f_entities | Flag::f_from_id;
|
auto bodyFlags = Flag::f_entities | Flag::f_from_id;
|
||||||
auto bodyReplyTo = 0;
|
auto bodyReplyTo = 0;
|
||||||
auto bodyViaBotId = 0;
|
auto bodyViaBotId = 0;
|
||||||
addPart(HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), { "participant toggle admin text", EntitiesInText() }));
|
auto bodyText = GenerateParticipantChangeText(channel(), action.vnew_participant, &action.vprev_participant);
|
||||||
|
addPart(HistoryMessage::create(_history, idManager.next(), bodyFlags, bodyReplyTo, bodyViaBotId, ::date(date), peerToUser(_from->id), bodyText));
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (action.type()) {
|
switch (action.type()) {
|
||||||
|
@ -263,19 +458,6 @@ HistoryTextState Item::getState(QPoint point, HistoryStateRequest request) const
|
||||||
return HistoryTextState();
|
return HistoryTextState();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextWithEntities Item::PrepareText(const QString &value, const QString &emptyValue) {
|
|
||||||
auto result = TextWithEntities { textClean(value) };
|
|
||||||
if (result.text.isEmpty()) {
|
|
||||||
result.text = emptyValue;
|
|
||||||
if (!emptyValue.isEmpty()) {
|
|
||||||
result.entities.push_back(EntityInText(EntityInTextItalic, 0, emptyValue.size()));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
textParseEntities(result.text, TextParseLinks | TextParseMentions | TextParseHashtags | TextParseBotCommands, &result.entities);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Item::~Item() {
|
Item::~Item() {
|
||||||
for (auto part : _parts) {
|
for (auto part : _parts) {
|
||||||
part->destroy();
|
part->destroy();
|
||||||
|
|
|
@ -54,8 +54,6 @@ private:
|
||||||
}
|
}
|
||||||
void addPart(HistoryItem *item);
|
void addPart(HistoryItem *item);
|
||||||
|
|
||||||
static TextWithEntities PrepareText(const QString &value, const QString &emptyValue);
|
|
||||||
|
|
||||||
uint64 _id = 0;
|
uint64 _id = 0;
|
||||||
gsl::not_null<History*> _history;
|
gsl::not_null<History*> _history;
|
||||||
gsl::not_null<UserData*> _from;
|
gsl::not_null<UserData*> _from;
|
||||||
|
|
|
@ -222,7 +222,7 @@ void HistoryFileMedia::checkAnimationFinished() const {
|
||||||
|
|
||||||
HistoryFileMedia::~HistoryFileMedia() = default;
|
HistoryFileMedia::~HistoryFileMedia() = default;
|
||||||
|
|
||||||
HistoryPhoto::HistoryPhoto(HistoryItem *parent, PhotoData *photo, const QString &caption) : HistoryFileMedia(parent)
|
HistoryPhoto::HistoryPhoto(gsl::not_null<HistoryItem*> parent, gsl::not_null<PhotoData*> photo, const QString &caption) : HistoryFileMedia(parent)
|
||||||
, _data(photo)
|
, _data(photo)
|
||||||
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) {
|
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) {
|
||||||
setLinks(MakeShared<PhotoOpenClickHandler>(_data), MakeShared<PhotoSaveClickHandler>(_data), MakeShared<PhotoCancelClickHandler>(_data));
|
setLinks(MakeShared<PhotoOpenClickHandler>(_data), MakeShared<PhotoSaveClickHandler>(_data), MakeShared<PhotoCancelClickHandler>(_data));
|
||||||
|
@ -232,15 +232,18 @@ HistoryPhoto::HistoryPhoto(HistoryItem *parent, PhotoData *photo, const QString
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryPhoto::HistoryPhoto(HistoryItem *parent, PeerData *chat, const MTPDphoto &photo, int32 width) : HistoryFileMedia(parent)
|
HistoryPhoto::HistoryPhoto(gsl::not_null<HistoryItem*> parent, gsl::not_null<PeerData*> chat, gsl::not_null<PhotoData*> photo, int32 width) : HistoryFileMedia(parent)
|
||||||
, _data(App::feedPhoto(photo)) {
|
, _data(photo) {
|
||||||
setLinks(MakeShared<PhotoOpenClickHandler>(_data, chat), MakeShared<PhotoSaveClickHandler>(_data, chat), MakeShared<PhotoCancelClickHandler>(_data, chat));
|
setLinks(MakeShared<PhotoOpenClickHandler>(_data, chat), MakeShared<PhotoSaveClickHandler>(_data, chat), MakeShared<PhotoCancelClickHandler>(_data, chat));
|
||||||
|
|
||||||
_width = width;
|
_width = width;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryPhoto::HistoryPhoto(HistoryItem *parent, const HistoryPhoto &other) : HistoryFileMedia(parent)
|
HistoryPhoto::HistoryPhoto(gsl::not_null<HistoryItem*> parent, gsl::not_null<PeerData*> chat, const MTPDphoto &photo, int32 width) : HistoryPhoto(parent, chat, App::feedPhoto(photo), width) {
|
||||||
|
}
|
||||||
|
|
||||||
|
HistoryPhoto::HistoryPhoto(gsl::not_null<HistoryItem*> parent, const HistoryPhoto &other) : HistoryFileMedia(parent)
|
||||||
, _data(other._data)
|
, _data(other._data)
|
||||||
, _pixw(other._pixw)
|
, _pixw(other._pixw)
|
||||||
, _pixh(other._pixh)
|
, _pixh(other._pixh)
|
||||||
|
@ -559,7 +562,7 @@ void HistoryPhoto::updateSentMedia(const MTPMessageMedia &media) {
|
||||||
|
|
||||||
bool HistoryPhoto::needReSetInlineResultMedia(const MTPMessageMedia &media) {
|
bool HistoryPhoto::needReSetInlineResultMedia(const MTPMessageMedia &media) {
|
||||||
if (media.type() == mtpc_messageMediaPhoto) {
|
if (media.type() == mtpc_messageMediaPhoto) {
|
||||||
if (PhotoData *existing = App::feedPhoto(media.c_messageMediaPhoto().vphoto)) {
|
if (auto existing = App::feedPhoto(media.c_messageMediaPhoto().vphoto)) {
|
||||||
if (existing == _data) {
|
if (existing == _data) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
@ -612,7 +615,7 @@ ImagePtr HistoryPhoto::replyPreview() {
|
||||||
return _data->makeReplyPreview();
|
return _data->makeReplyPreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryVideo::HistoryVideo(HistoryItem *parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent)
|
HistoryVideo::HistoryVideo(gsl::not_null<HistoryItem*> parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent)
|
||||||
, _data(document)
|
, _data(document)
|
||||||
, _thumbw(1)
|
, _thumbw(1)
|
||||||
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) {
|
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) {
|
||||||
|
@ -627,7 +630,7 @@ HistoryVideo::HistoryVideo(HistoryItem *parent, DocumentData *document, const QS
|
||||||
_data->thumb->load();
|
_data->thumb->load();
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryVideo::HistoryVideo(HistoryItem *parent, const HistoryVideo &other) : HistoryFileMedia(parent)
|
HistoryVideo::HistoryVideo(gsl::not_null<HistoryItem*> parent, const HistoryVideo &other) : HistoryFileMedia(parent)
|
||||||
, _data(other._data)
|
, _data(other._data)
|
||||||
, _thumbw(other._thumbw)
|
, _thumbw(other._thumbw)
|
||||||
, _caption(other._caption) {
|
, _caption(other._caption) {
|
||||||
|
@ -976,7 +979,7 @@ void HistoryDocumentVoice::stopSeeking() {
|
||||||
Media::Player::instance()->stopSeeking(AudioMsgId::Type::Voice);
|
Media::Player::instance()->stopSeeking(AudioMsgId::Type::Voice);
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryDocument::HistoryDocument(HistoryItem *parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent)
|
HistoryDocument::HistoryDocument(gsl::not_null<HistoryItem*> parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent)
|
||||||
, _data(document) {
|
, _data(document) {
|
||||||
createComponents(!caption.isEmpty());
|
createComponents(!caption.isEmpty());
|
||||||
if (auto named = Get<HistoryDocumentNamed>()) {
|
if (auto named = Get<HistoryDocumentNamed>()) {
|
||||||
|
@ -992,7 +995,7 @@ HistoryDocument::HistoryDocument(HistoryItem *parent, DocumentData *document, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryDocument::HistoryDocument(HistoryItem *parent, const HistoryDocument &other) : HistoryFileMedia(parent)
|
HistoryDocument::HistoryDocument(gsl::not_null<HistoryItem*> parent, const HistoryDocument &other) : HistoryFileMedia(parent)
|
||||||
, RuntimeComposer()
|
, RuntimeComposer()
|
||||||
, _data(other._data) {
|
, _data(other._data) {
|
||||||
auto captioned = other.Get<HistoryDocumentCaptioned>();
|
auto captioned = other.Get<HistoryDocumentCaptioned>();
|
||||||
|
@ -1715,7 +1718,7 @@ ImagePtr HistoryDocument::replyPreview() {
|
||||||
return _data->makeReplyPreview();
|
return _data->makeReplyPreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryGif::HistoryGif(HistoryItem *parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent)
|
HistoryGif::HistoryGif(gsl::not_null<HistoryItem*> parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent)
|
||||||
, _data(document)
|
, _data(document)
|
||||||
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) {
|
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) {
|
||||||
setDocumentLinks(_data, true);
|
setDocumentLinks(_data, true);
|
||||||
|
@ -1730,7 +1733,7 @@ HistoryGif::HistoryGif(HistoryItem *parent, DocumentData *document, const QStrin
|
||||||
_data->thumb->load();
|
_data->thumb->load();
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryGif::HistoryGif(HistoryItem *parent, const HistoryGif &other) : HistoryFileMedia(parent)
|
HistoryGif::HistoryGif(gsl::not_null<HistoryItem*> parent, const HistoryGif &other) : HistoryFileMedia(parent)
|
||||||
, _data(other._data)
|
, _data(other._data)
|
||||||
, _thumbw(other._thumbw)
|
, _thumbw(other._thumbw)
|
||||||
, _thumbh(other._thumbh)
|
, _thumbh(other._thumbh)
|
||||||
|
@ -2488,7 +2491,7 @@ bool HistoryGif::dataLoaded() const {
|
||||||
return (!_parent || _parent->id > 0) ? _data->loaded() : false;
|
return (!_parent || _parent->id > 0) ? _data->loaded() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
HistorySticker::HistorySticker(HistoryItem *parent, DocumentData *document) : HistoryMedia(parent)
|
HistorySticker::HistorySticker(gsl::not_null<HistoryItem*> parent, DocumentData *document) : HistoryMedia(parent)
|
||||||
, _data(document)
|
, _data(document)
|
||||||
, _emoji(_data->sticker()->alt) {
|
, _emoji(_data->sticker()->alt) {
|
||||||
_data->thumb->load();
|
_data->thumb->load();
|
||||||
|
@ -2770,7 +2773,7 @@ ClickHandlerPtr addContactClickHandler(HistoryItem *item) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
HistoryContact::HistoryContact(HistoryItem *parent, int32 userId, const QString &first, const QString &last, const QString &phone) : HistoryMedia(parent)
|
HistoryContact::HistoryContact(gsl::not_null<HistoryItem*> parent, int32 userId, const QString &first, const QString &last, const QString &phone) : HistoryMedia(parent)
|
||||||
, _userId(userId)
|
, _userId(userId)
|
||||||
, _fname(first)
|
, _fname(first)
|
||||||
, _lname(last)
|
, _lname(last)
|
||||||
|
@ -2936,7 +2939,7 @@ void HistoryContact::updateSentMedia(const MTPMessageMedia &media) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryCall::HistoryCall(HistoryItem *parent, const MTPDmessageActionPhoneCall &call) : HistoryMedia(parent)
|
HistoryCall::HistoryCall(gsl::not_null<HistoryItem*> parent, const MTPDmessageActionPhoneCall &call) : HistoryMedia(parent)
|
||||||
, _reason(GetReason(call)) {
|
, _reason(GetReason(call)) {
|
||||||
if (_parent->out()) {
|
if (_parent->out()) {
|
||||||
_text = lang(_reason == FinishReason::Missed ? lng_call_cancelled : lng_call_outgoing);
|
_text = lang(_reason == FinishReason::Missed ? lng_call_cancelled : lng_call_outgoing);
|
||||||
|
@ -3087,13 +3090,13 @@ int unitedLineHeight() {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
HistoryWebPage::HistoryWebPage(HistoryItem *parent, WebPageData *data) : HistoryMedia(parent)
|
HistoryWebPage::HistoryWebPage(gsl::not_null<HistoryItem*> parent, WebPageData *data) : HistoryMedia(parent)
|
||||||
, _data(data)
|
, _data(data)
|
||||||
, _title(st::msgMinWidth - st::webPageLeft)
|
, _title(st::msgMinWidth - st::webPageLeft)
|
||||||
, _description(st::msgMinWidth - st::webPageLeft) {
|
, _description(st::msgMinWidth - st::webPageLeft) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryWebPage::HistoryWebPage(HistoryItem *parent, const HistoryWebPage &other) : HistoryMedia(parent)
|
HistoryWebPage::HistoryWebPage(gsl::not_null<HistoryItem*> parent, const HistoryWebPage &other) : HistoryMedia(parent)
|
||||||
, _data(other._data)
|
, _data(other._data)
|
||||||
, _attach(other._attach ? other._attach->clone(parent) : nullptr)
|
, _attach(other._attach ? other._attach->clone(parent) : nullptr)
|
||||||
, _asArticle(other._asArticle)
|
, _asArticle(other._asArticle)
|
||||||
|
@ -3613,13 +3616,13 @@ int HistoryWebPage::bottomInfoPadding() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryGame::HistoryGame(HistoryItem *parent, GameData *data) : HistoryMedia(parent)
|
HistoryGame::HistoryGame(gsl::not_null<HistoryItem*> parent, GameData *data) : HistoryMedia(parent)
|
||||||
, _data(data)
|
, _data(data)
|
||||||
, _title(st::msgMinWidth - st::webPageLeft)
|
, _title(st::msgMinWidth - st::webPageLeft)
|
||||||
, _description(st::msgMinWidth - st::webPageLeft) {
|
, _description(st::msgMinWidth - st::webPageLeft) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryGame::HistoryGame(HistoryItem *parent, const HistoryGame &other) : HistoryMedia(parent)
|
HistoryGame::HistoryGame(gsl::not_null<HistoryItem*> parent, const HistoryGame &other) : HistoryMedia(parent)
|
||||||
, _data(other._data)
|
, _data(other._data)
|
||||||
, _attach(other._attach ? other._attach->clone(parent) : nullptr)
|
, _attach(other._attach ? other._attach->clone(parent) : nullptr)
|
||||||
, _title(other._title)
|
, _title(other._title)
|
||||||
|
@ -3992,14 +3995,14 @@ int HistoryGame::bottomInfoPadding() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryInvoice::HistoryInvoice(HistoryItem *parent, const MTPDmessageMediaInvoice &data) : HistoryMedia(parent)
|
HistoryInvoice::HistoryInvoice(gsl::not_null<HistoryItem*> parent, const MTPDmessageMediaInvoice &data) : HistoryMedia(parent)
|
||||||
, _title(st::msgMinWidth)
|
, _title(st::msgMinWidth)
|
||||||
, _description(st::msgMinWidth)
|
, _description(st::msgMinWidth)
|
||||||
, _status(st::msgMinWidth) {
|
, _status(st::msgMinWidth) {
|
||||||
fillFromData(data);
|
fillFromData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryInvoice::HistoryInvoice(HistoryItem *parent, const HistoryInvoice &other) : HistoryMedia(parent)
|
HistoryInvoice::HistoryInvoice(gsl::not_null<HistoryItem*> parent, const HistoryInvoice &other) : HistoryMedia(parent)
|
||||||
, _attach(other._attach ? other._attach->clone(parent) : nullptr)
|
, _attach(other._attach ? other._attach->clone(parent) : nullptr)
|
||||||
, _titleHeight(other._titleHeight)
|
, _titleHeight(other._titleHeight)
|
||||||
, _descriptionHeight(other._descriptionHeight)
|
, _descriptionHeight(other._descriptionHeight)
|
||||||
|
@ -4371,7 +4374,7 @@ int HistoryInvoice::bottomInfoPadding() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryLocation::HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title, const QString &description) : HistoryMedia(parent)
|
HistoryLocation::HistoryLocation(gsl::not_null<HistoryItem*> parent, const LocationCoords &coords, const QString &title, const QString &description) : HistoryMedia(parent)
|
||||||
, _data(App::location(coords))
|
, _data(App::location(coords))
|
||||||
, _title(st::msgMinWidth)
|
, _title(st::msgMinWidth)
|
||||||
, _description(st::msgMinWidth)
|
, _description(st::msgMinWidth)
|
||||||
|
@ -4384,7 +4387,7 @@ HistoryLocation::HistoryLocation(HistoryItem *parent, const LocationCoords &coor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryLocation::HistoryLocation(HistoryItem *parent, const HistoryLocation &other) : HistoryMedia(parent)
|
HistoryLocation::HistoryLocation(gsl::not_null<HistoryItem*> parent, const HistoryLocation &other) : HistoryMedia(parent)
|
||||||
, _data(other._data)
|
, _data(other._data)
|
||||||
, _title(other._title)
|
, _title(other._title)
|
||||||
, _description(other._description)
|
, _description(other._description)
|
||||||
|
|
|
@ -116,9 +116,10 @@ protected:
|
||||||
|
|
||||||
class HistoryPhoto : public HistoryFileMedia {
|
class HistoryPhoto : public HistoryFileMedia {
|
||||||
public:
|
public:
|
||||||
HistoryPhoto(HistoryItem *parent, PhotoData *photo, const QString &caption);
|
HistoryPhoto(gsl::not_null<HistoryItem*> parent, gsl::not_null<PhotoData*> photo, const QString &caption);
|
||||||
HistoryPhoto(HistoryItem *parent, PeerData *chat, const MTPDphoto &photo, int width);
|
HistoryPhoto(gsl::not_null<HistoryItem*> parent, gsl::not_null<PeerData*> chat, gsl::not_null<PhotoData*> photo, int width);
|
||||||
HistoryPhoto(HistoryItem *parent, const HistoryPhoto &other);
|
HistoryPhoto(gsl::not_null<HistoryItem*> parent, gsl::not_null<PeerData*> chat, const MTPDphoto &photo, int width);
|
||||||
|
HistoryPhoto(gsl::not_null<HistoryItem*> parent, const HistoryPhoto &other);
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
|
@ -212,8 +213,8 @@ private:
|
||||||
|
|
||||||
class HistoryVideo : public HistoryFileMedia {
|
class HistoryVideo : public HistoryFileMedia {
|
||||||
public:
|
public:
|
||||||
HistoryVideo(HistoryItem *parent, DocumentData *document, const QString &caption);
|
HistoryVideo(gsl::not_null<HistoryItem*> parent, DocumentData *document, const QString &caption);
|
||||||
HistoryVideo(HistoryItem *parent, const HistoryVideo &other);
|
HistoryVideo(gsl::not_null<HistoryItem*> parent, const HistoryVideo &other);
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
return MediaTypeVideo;
|
return MediaTypeVideo;
|
||||||
}
|
}
|
||||||
|
@ -370,8 +371,8 @@ private:
|
||||||
|
|
||||||
class HistoryDocument : public HistoryFileMedia, public RuntimeComposer {
|
class HistoryDocument : public HistoryFileMedia, public RuntimeComposer {
|
||||||
public:
|
public:
|
||||||
HistoryDocument(HistoryItem *parent, DocumentData *document, const QString &caption);
|
HistoryDocument(gsl::not_null<HistoryItem*> parent, DocumentData *document, const QString &caption);
|
||||||
HistoryDocument(HistoryItem *parent, const HistoryDocument &other);
|
HistoryDocument(gsl::not_null<HistoryItem*> parent, const HistoryDocument &other);
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
return _data->voice() ? MediaTypeVoiceFile : (_data->song() ? MediaTypeMusicFile : MediaTypeFile);
|
return _data->voice() ? MediaTypeVoiceFile : (_data->song() ? MediaTypeMusicFile : MediaTypeFile);
|
||||||
}
|
}
|
||||||
|
@ -477,8 +478,8 @@ private:
|
||||||
|
|
||||||
class HistoryGif : public HistoryFileMedia {
|
class HistoryGif : public HistoryFileMedia {
|
||||||
public:
|
public:
|
||||||
HistoryGif(HistoryItem *parent, DocumentData *document, const QString &caption);
|
HistoryGif(gsl::not_null<HistoryItem*> parent, DocumentData *document, const QString &caption);
|
||||||
HistoryGif(HistoryItem *parent, const HistoryGif &other);
|
HistoryGif(gsl::not_null<HistoryItem*> parent, const HistoryGif &other);
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
return MediaTypeGif;
|
return MediaTypeGif;
|
||||||
}
|
}
|
||||||
|
@ -601,7 +602,7 @@ private:
|
||||||
|
|
||||||
class HistorySticker : public HistoryMedia {
|
class HistorySticker : public HistoryMedia {
|
||||||
public:
|
public:
|
||||||
HistorySticker(HistoryItem *parent, DocumentData *document);
|
HistorySticker(gsl::not_null<HistoryItem*> parent, DocumentData *document);
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
return MediaTypeSticker;
|
return MediaTypeSticker;
|
||||||
}
|
}
|
||||||
|
@ -670,7 +671,7 @@ private:
|
||||||
|
|
||||||
class HistoryContact : public HistoryMedia {
|
class HistoryContact : public HistoryMedia {
|
||||||
public:
|
public:
|
||||||
HistoryContact(HistoryItem *parent, int32 userId, const QString &first, const QString &last, const QString &phone);
|
HistoryContact(gsl::not_null<HistoryItem*> parent, int32 userId, const QString &first, const QString &last, const QString &phone);
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
return MediaTypeContact;
|
return MediaTypeContact;
|
||||||
}
|
}
|
||||||
|
@ -732,7 +733,7 @@ private:
|
||||||
|
|
||||||
class HistoryCall : public HistoryMedia {
|
class HistoryCall : public HistoryMedia {
|
||||||
public:
|
public:
|
||||||
HistoryCall(HistoryItem *parent, const MTPDmessageActionPhoneCall &call);
|
HistoryCall(gsl::not_null<HistoryItem*> parent, const MTPDmessageActionPhoneCall &call);
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
return MediaTypeCall;
|
return MediaTypeCall;
|
||||||
}
|
}
|
||||||
|
@ -787,8 +788,8 @@ private:
|
||||||
|
|
||||||
class HistoryWebPage : public HistoryMedia {
|
class HistoryWebPage : public HistoryMedia {
|
||||||
public:
|
public:
|
||||||
HistoryWebPage(HistoryItem *parent, WebPageData *data);
|
HistoryWebPage(gsl::not_null<HistoryItem*> parent, WebPageData *data);
|
||||||
HistoryWebPage(HistoryItem *parent, const HistoryWebPage &other);
|
HistoryWebPage(gsl::not_null<HistoryItem*> parent, const HistoryWebPage &other);
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
return MediaTypeWebPage;
|
return MediaTypeWebPage;
|
||||||
}
|
}
|
||||||
|
@ -886,8 +887,8 @@ private:
|
||||||
|
|
||||||
class HistoryGame : public HistoryMedia {
|
class HistoryGame : public HistoryMedia {
|
||||||
public:
|
public:
|
||||||
HistoryGame(HistoryItem *parent, GameData *data);
|
HistoryGame(gsl::not_null<HistoryItem*> parent, GameData *data);
|
||||||
HistoryGame(HistoryItem *parent, const HistoryGame &other);
|
HistoryGame(gsl::not_null<HistoryItem*> parent, const HistoryGame &other);
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
return MediaTypeGame;
|
return MediaTypeGame;
|
||||||
}
|
}
|
||||||
|
@ -986,8 +987,8 @@ private:
|
||||||
|
|
||||||
class HistoryInvoice : public HistoryMedia {
|
class HistoryInvoice : public HistoryMedia {
|
||||||
public:
|
public:
|
||||||
HistoryInvoice(HistoryItem *parent, const MTPDmessageMediaInvoice &data);
|
HistoryInvoice(gsl::not_null<HistoryItem*> parent, const MTPDmessageMediaInvoice &data);
|
||||||
HistoryInvoice(HistoryItem *parent, const HistoryInvoice &other);
|
HistoryInvoice(gsl::not_null<HistoryItem*> parent, const HistoryInvoice &other);
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
return MediaTypeInvoice;
|
return MediaTypeInvoice;
|
||||||
}
|
}
|
||||||
|
@ -1077,8 +1078,8 @@ struct LocationData;
|
||||||
|
|
||||||
class HistoryLocation : public HistoryMedia {
|
class HistoryLocation : public HistoryMedia {
|
||||||
public:
|
public:
|
||||||
HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title = QString(), const QString &description = QString());
|
HistoryLocation(gsl::not_null<HistoryItem*> parent, const LocationCoords &coords, const QString &title = QString(), const QString &description = QString());
|
||||||
HistoryLocation(HistoryItem *parent, const HistoryLocation &other);
|
HistoryLocation(gsl::not_null<HistoryItem*> parent, const HistoryLocation &other);
|
||||||
HistoryMediaType type() const override {
|
HistoryMediaType type() const override {
|
||||||
return MediaTypeLocation;
|
return MediaTypeLocation;
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,11 +425,9 @@ HistoryMessage::HistoryMessage(History *history, const MTPDmessage &msg)
|
||||||
|
|
||||||
initMedia(msg.has_media() ? (&msg.vmedia) : nullptr);
|
initMedia(msg.has_media() ? (&msg.vmedia) : nullptr);
|
||||||
|
|
||||||
TextWithEntities textWithEntities = {
|
auto text = textClean(qs(msg.vmessage));
|
||||||
textClean(qs(msg.vmessage)),
|
auto entities = msg.has_entities() ? entitiesFromMTP(msg.ventities.v) : EntitiesInText();
|
||||||
msg.has_entities() ? entitiesFromMTP(msg.ventities.v) : EntitiesInText(),
|
setText({ text, entities });
|
||||||
};
|
|
||||||
setText(textWithEntities);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryMessage::HistoryMessage(History *history, const MTPDmessageService &msg)
|
HistoryMessage::HistoryMessage(History *history, const MTPDmessageService &msg)
|
||||||
|
@ -2214,9 +2212,12 @@ HistoryService::HistoryService(History *history, const MTPDmessageService &messa
|
||||||
setMessageByAction(message.vaction);
|
setMessageByAction(message.vaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryService::HistoryService(History *history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags, int32 from) :
|
HistoryService::HistoryService(History *history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags, int32 from, PhotoData *photo) :
|
||||||
HistoryItem(history, msgId, flags, date, from) {
|
HistoryItem(history, msgId, flags, date, from) {
|
||||||
setServiceText(message);
|
setServiceText(message);
|
||||||
|
if (photo) {
|
||||||
|
_media = std::make_unique<HistoryPhoto>(this, history->peer, photo, st::msgServicePhotoWidth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryService::initDimensions() {
|
void HistoryService::initDimensions() {
|
||||||
|
|
|
@ -281,8 +281,8 @@ public:
|
||||||
static HistoryService *create(History *history, const MTPDmessageService &message) {
|
static HistoryService *create(History *history, const MTPDmessageService &message) {
|
||||||
return _create(history, message);
|
return _create(history, message);
|
||||||
}
|
}
|
||||||
static HistoryService *create(History *history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags = 0, int32 from = 0) {
|
static HistoryService *create(History *history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags = 0, UserId from = 0, PhotoData *photo = nullptr) {
|
||||||
return _create(history, msgId, date, message, flags, from);
|
return _create(history, msgId, date, message, flags, from, photo);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool updateDependencyItem() override;
|
bool updateDependencyItem() override;
|
||||||
|
@ -339,7 +339,7 @@ protected:
|
||||||
friend class HistoryLayout::ServiceMessagePainter;
|
friend class HistoryLayout::ServiceMessagePainter;
|
||||||
|
|
||||||
HistoryService(History *history, const MTPDmessageService &message);
|
HistoryService(History *history, const MTPDmessageService &message);
|
||||||
HistoryService(History *history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags = 0, int32 from = 0);
|
HistoryService(History *history, MsgId msgId, QDateTime date, const PreparedText &message, MTPDmessage::Flags flags = 0, UserId from = 0, PhotoData *photo = 0);
|
||||||
friend class HistoryItemInstantiated<HistoryService>;
|
friend class HistoryItemInstantiated<HistoryService>;
|
||||||
|
|
||||||
void initDimensions() override;
|
void initDimensions() override;
|
||||||
|
|
|
@ -129,19 +129,14 @@ ChoosePluralMethod ChoosePlural = ChoosePluralEn;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
QString Tag(const QString &original, ushort tag, const QString &replacement) {
|
int FindTagReplacementPosition(const QString &original, ushort tag) {
|
||||||
for (auto s = original.constData(), ch = s, e = ch + original.size(); ch != e;) {
|
for (auto s = original.constData(), ch = s, e = ch + original.size(); ch != e;) {
|
||||||
if (*ch == TextCommand) {
|
if (*ch == TextCommand) {
|
||||||
if (ch + 3 < e && (ch + 1)->unicode() == TextCommandLangTag && *(ch + 3) == TextCommand) {
|
if (ch + kTagReplacementSize <= e && (ch + 1)->unicode() == TextCommandLangTag && *(ch + 3) == TextCommand) {
|
||||||
if ((ch + 2)->unicode() == 0x0020 + tag) {
|
if ((ch + 2)->unicode() == 0x0020 + tag) {
|
||||||
auto result = QString();
|
return ch - s;
|
||||||
result.reserve(original.size() + replacement.size() - 4);
|
|
||||||
if (ch > s) result.append(original.midRef(0, ch - s));
|
|
||||||
result.append(replacement);
|
|
||||||
if (ch + 4 < e) result.append(original.midRef(ch - s + 4));
|
|
||||||
return result;
|
|
||||||
} else {
|
} else {
|
||||||
ch += 4;
|
ch += kTagReplacementSize;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto next = textSkipCommand(ch, e);
|
auto next = textSkipCommand(ch, e);
|
||||||
|
@ -155,10 +150,11 @@ QString Tag(const QString &original, ushort tag, const QString &replacement) {
|
||||||
++ch;
|
++ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return original;
|
return -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Plural(ushort keyBase, ushort tag, float64 value) {
|
PluralResult Plural(ushort keyBase, float64 value) {
|
||||||
// Simplified.
|
// Simplified.
|
||||||
auto n = qAbs(value);
|
auto n = qAbs(value);
|
||||||
auto i = qFloor(n);
|
auto i = qFloor(n);
|
||||||
|
@ -173,9 +169,9 @@ QString Plural(ushort keyBase, ushort tag, float64 value) {
|
||||||
auto shift = (useNonDefaultPlural ? ChoosePlural : ChoosePluralEn)((integer ? i : -1), i, v, w, f, t);
|
auto shift = (useNonDefaultPlural ? ChoosePlural : ChoosePluralEn)((integer ? i : -1), i, v, w, f, t);
|
||||||
auto string = langpack.getValue(LangKey(keyBase + shift));
|
auto string = langpack.getValue(LangKey(keyBase + shift));
|
||||||
if (i == qCeil(n)) {
|
if (i == qCeil(n)) {
|
||||||
return Tag(string, tag, QString::number(value));
|
return { string, QString::number(value) };
|
||||||
}
|
}
|
||||||
return Tag(string, tag, QString::number(qRound(value)));
|
return { string, QString::number(qRound(value)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdatePluralRules(const QString &languageId) {
|
void UpdatePluralRules(const QString &languageId) {
|
||||||
|
@ -183,4 +179,17 @@ void UpdatePluralRules(const QString &languageId) {
|
||||||
ChoosePlural = kMap.value(languageId.toLower(), ChoosePluralEn);
|
ChoosePlural = kMap.value(languageId.toLower(), ChoosePluralEn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ReplaceTag<QString>::Replace(QString &&original, const QString &replacement, int replacementPosition) {
|
||||||
|
auto result = QString();
|
||||||
|
result.reserve(original.size() + replacement.size() - kTagReplacementSize);
|
||||||
|
if (replacementPosition > 0) {
|
||||||
|
result.append(original.midRef(0, replacementPosition));
|
||||||
|
}
|
||||||
|
result.append(replacement);
|
||||||
|
if (replacementPosition + kTagReplacementSize < original.size()) {
|
||||||
|
result.append(original.midRef(replacementPosition + kTagReplacementSize));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Lang
|
} // namespace Lang
|
||||||
|
|
|
@ -22,8 +22,41 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
namespace Lang {
|
namespace Lang {
|
||||||
|
|
||||||
QString Tag(const QString &original, ushort tag, const QString &replacement);
|
constexpr auto kTagReplacementSize = 4;
|
||||||
QString Plural(ushort keyBase, ushort tag, float64 value);
|
|
||||||
|
int FindTagReplacementPosition(const QString &original, ushort tag);
|
||||||
|
|
||||||
|
struct PluralResult {
|
||||||
|
QString string;
|
||||||
|
QString replacement;
|
||||||
|
};
|
||||||
|
PluralResult Plural(ushort keyBase, float64 value);
|
||||||
void UpdatePluralRules(const QString &languageId);
|
void UpdatePluralRules(const QString &languageId);
|
||||||
|
|
||||||
|
template <typename ResultString>
|
||||||
|
struct StartReplacements;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct StartReplacements<QString> {
|
||||||
|
static inline QString Call(QString &&langString) {
|
||||||
|
return std::move(langString);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ResultString>
|
||||||
|
struct ReplaceTag;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ReplaceTag<QString> {
|
||||||
|
static inline QString Call(QString &&original, ushort tag, const QString &replacement) {
|
||||||
|
auto replacementPosition = FindTagReplacementPosition(original, tag);
|
||||||
|
if (replacementPosition < 0) {
|
||||||
|
return std::move(original);
|
||||||
|
}
|
||||||
|
return Replace(std::move(original), replacement, replacementPosition);
|
||||||
|
}
|
||||||
|
static QString Replace(QString &&original, const QString &replacement, int start);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Lang
|
} // namespace Lang
|
||||||
|
|
|
@ -801,6 +801,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static MTPChannelBannedRights KickedRestrictedRights();
|
static MTPChannelBannedRights KickedRestrictedRights();
|
||||||
|
static constexpr auto kRestrictUntilForever = TimeId(INT_MAX);
|
||||||
|
static bool IsRestrictedForever(TimeId until) {
|
||||||
|
return !until || (until == kRestrictUntilForever);
|
||||||
|
}
|
||||||
void applyEditAdmin(gsl::not_null<UserData*> user, const MTPChannelAdminRights &rights);
|
void applyEditAdmin(gsl::not_null<UserData*> user, const MTPChannelAdminRights &rights);
|
||||||
void applyEditBanned(gsl::not_null<UserData*> user, const MTPChannelBannedRights &rights);
|
void applyEditBanned(gsl::not_null<UserData*> user, const MTPChannelBannedRights &rights);
|
||||||
|
|
||||||
|
@ -1117,9 +1121,9 @@ private:
|
||||||
|
|
||||||
class PhotoClickHandler : public LeftButtonClickHandler {
|
class PhotoClickHandler : public LeftButtonClickHandler {
|
||||||
public:
|
public:
|
||||||
PhotoClickHandler(PhotoData *photo, PeerData *peer = 0) : _photo(photo), _peer(peer) {
|
PhotoClickHandler(gsl::not_null<PhotoData*> photo, PeerData *peer = nullptr) : _photo(photo), _peer(peer) {
|
||||||
}
|
}
|
||||||
PhotoData *photo() const {
|
gsl::not_null<PhotoData*> photo() const {
|
||||||
return _photo;
|
return _photo;
|
||||||
}
|
}
|
||||||
PeerData *peer() const {
|
PeerData *peer() const {
|
||||||
|
@ -1127,7 +1131,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PhotoData *_photo;
|
gsl::not_null<PhotoData*> _photo;
|
||||||
PeerData *_peer;
|
PeerData *_peer;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/text/text_entity.h"
|
#include "ui/text/text_entity.h"
|
||||||
|
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
|
#include "lang/lang_tag.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -1366,7 +1367,7 @@ EntitiesInText entitiesFromMTP(const QVector<MTPMessageEntity> &entities) {
|
||||||
case mtpc_messageEntityHashtag: { const auto &d(entity.c_messageEntityHashtag()); result.push_back(EntityInText(EntityInTextHashtag, d.voffset.v, d.vlength.v)); } break;
|
case mtpc_messageEntityHashtag: { const auto &d(entity.c_messageEntityHashtag()); result.push_back(EntityInText(EntityInTextHashtag, d.voffset.v, d.vlength.v)); } break;
|
||||||
case mtpc_messageEntityMention: { const auto &d(entity.c_messageEntityMention()); result.push_back(EntityInText(EntityInTextMention, d.voffset.v, d.vlength.v)); } break;
|
case mtpc_messageEntityMention: { const auto &d(entity.c_messageEntityMention()); result.push_back(EntityInText(EntityInTextMention, d.voffset.v, d.vlength.v)); } break;
|
||||||
case mtpc_messageEntityMentionName: {
|
case mtpc_messageEntityMentionName: {
|
||||||
const auto &d(entity.c_messageEntityMentionName());
|
auto &d = entity.c_messageEntityMentionName();
|
||||||
auto data = QString::number(d.vuser_id.v);
|
auto data = QString::number(d.vuser_id.v);
|
||||||
if (auto user = App::userLoaded(peerFromUser(d.vuser_id))) {
|
if (auto user = App::userLoaded(peerFromUser(d.vuser_id))) {
|
||||||
data += '.' + QString::number(user->access);
|
data += '.' + QString::number(user->access);
|
||||||
|
@ -1374,7 +1375,7 @@ EntitiesInText entitiesFromMTP(const QVector<MTPMessageEntity> &entities) {
|
||||||
result.push_back(EntityInText(EntityInTextMentionName, d.voffset.v, d.vlength.v, data));
|
result.push_back(EntityInText(EntityInTextMentionName, d.voffset.v, d.vlength.v, data));
|
||||||
} break;
|
} break;
|
||||||
case mtpc_inputMessageEntityMentionName: {
|
case mtpc_inputMessageEntityMentionName: {
|
||||||
const auto &d(entity.c_inputMessageEntityMentionName());
|
auto &d = entity.c_inputMessageEntityMentionName();
|
||||||
auto data = ([&d]() -> QString {
|
auto data = ([&d]() -> QString {
|
||||||
if (d.vuser_id.type() == mtpc_inputUserSelf) {
|
if (d.vuser_id.type() == mtpc_inputUserSelf) {
|
||||||
return QString::number(AuthSession::CurrentUserId());
|
return QString::number(AuthSession::CurrentUserId());
|
||||||
|
@ -1994,3 +1995,65 @@ void trimTextWithEntities(QString &result, EntitiesInText *inOutEntities) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Lang {
|
||||||
|
|
||||||
|
TextWithEntities ReplaceTag<TextWithEntities>::Call(TextWithEntities &&original, ushort tag, const TextWithEntities &replacement) {
|
||||||
|
auto replacementPosition = FindTagReplacementPosition(original.text, tag);
|
||||||
|
if (replacementPosition < 0) {
|
||||||
|
return std::move(original);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = TextWithEntities();
|
||||||
|
result.text = ReplaceTag<QString>::Replace(std::move(original.text), replacement.text, replacementPosition);
|
||||||
|
auto originalEntitiesCount = original.entities.size();
|
||||||
|
auto replacementEntitiesCount = replacement.entities.size();
|
||||||
|
if (originalEntitiesCount != 0 || replacementEntitiesCount != 0) {
|
||||||
|
result.entities.reserve(originalEntitiesCount + replacementEntitiesCount);
|
||||||
|
|
||||||
|
auto replacementEnd = replacementPosition + replacement.text.size();
|
||||||
|
auto replacementEntity = replacement.entities.cbegin();
|
||||||
|
auto addReplacementEntitiesUntil = [&replacementEntity, &replacement, &result, replacementPosition, replacementEnd](int untilPosition) {
|
||||||
|
while (replacementEntity != replacement.entities.cend()) {
|
||||||
|
auto newOffset = replacementPosition + replacementEntity->offset();
|
||||||
|
if (newOffset >= untilPosition) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto newEnd = newOffset + replacementEntity->length();
|
||||||
|
newOffset = snap(newOffset, replacementPosition, replacementEnd);
|
||||||
|
newEnd = snap(newEnd, replacementPosition, replacementEnd);
|
||||||
|
if (auto newLength = newEnd - newOffset) {
|
||||||
|
result.entities.push_back(EntityInText(replacementEntity->type(), newOffset, newLength, replacementEntity->data()));
|
||||||
|
}
|
||||||
|
++replacementEntity;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for_const (auto &entity, original.entities) {
|
||||||
|
// Transform the entity by the replacement.
|
||||||
|
auto offset = entity.offset();
|
||||||
|
auto end = offset + entity.length();
|
||||||
|
if (offset > replacementPosition) {
|
||||||
|
offset = offset + replacement.text.size() - kTagReplacementSize;
|
||||||
|
}
|
||||||
|
if (end > replacementPosition) {
|
||||||
|
end = end + replacement.text.size() - kTagReplacementSize;
|
||||||
|
}
|
||||||
|
offset = snap(offset, 0, result.text.size());
|
||||||
|
end = snap(end, 0, result.text.size());
|
||||||
|
|
||||||
|
// Add all replacement entities that start before the current original entity.
|
||||||
|
addReplacementEntitiesUntil(offset);
|
||||||
|
|
||||||
|
// Add a modified original entity.
|
||||||
|
if (auto length = end - offset) {
|
||||||
|
result.entities.push_back(EntityInText(entity.type(), offset, length, entity.data()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add the remaining replacement entities.
|
||||||
|
addReplacementEntitiesUntil(result.text.size());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Lang
|
||||||
|
|
|
@ -180,4 +180,27 @@ inline QString prepareText(QString result, bool checkLinks = false) {
|
||||||
|
|
||||||
// replace bad symbols with space and remove \r
|
// replace bad symbols with space and remove \r
|
||||||
void cleanTextWithEntities(QString &result, EntitiesInText *inOutEntities);
|
void cleanTextWithEntities(QString &result, EntitiesInText *inOutEntities);
|
||||||
void trimTextWithEntities(QString &result, EntitiesInText *inOutEntities);
|
void trimTextWithEntities(QString &result, EntitiesInText *inOutEntities);
|
||||||
|
|
||||||
|
namespace Lang {
|
||||||
|
|
||||||
|
template <typename ResultString>
|
||||||
|
struct StartReplacements;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct StartReplacements<TextWithEntities> {
|
||||||
|
static inline TextWithEntities Call(QString &&langString) {
|
||||||
|
return { std::move(langString), EntitiesInText() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ResultString>
|
||||||
|
struct ReplaceTag;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ReplaceTag<TextWithEntities> {
|
||||||
|
static TextWithEntities Call(TextWithEntities &&original, ushort tag, const TextWithEntities &replacement);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -650,7 +650,8 @@ void ThemeExportBox::chooseBackgroundFromFile() {
|
||||||
_background = image;
|
_background = image;
|
||||||
_backgroundContent = content;
|
_backgroundContent = content;
|
||||||
_isPng = (format == "png");
|
_isPng = (format == "png");
|
||||||
_imageText = (_isPng ? lng_theme_editor_read_from_png : lng_theme_editor_read_from_jpg)(lt_size, formatSizeText(_backgroundContent.size()));
|
auto sizeText = formatSizeText(_backgroundContent.size());
|
||||||
|
_imageText = _isPng ? lng_theme_editor_read_from_png(lt_size, sizeText) : lng_theme_editor_read_from_jpg(lt_size, sizeText);
|
||||||
_tileBackground->setChecked(false);
|
_tileBackground->setChecked(false);
|
||||||
updateThumbnail();
|
updateThumbnail();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue