Update API scheme to layer 198.

This commit is contained in:
John Preston 2025-01-09 11:24:54 +04:00
parent 37d32b32f8
commit d0132c0f7b
25 changed files with 251 additions and 114 deletions

View file

@ -283,6 +283,7 @@ mtpRequestId EditTextMessage(
return MTP_inputMediaDocument(
MTP_flags(flags),
document->mtpInput(),
MTPInputPhoto(), // video_cover
MTP_int(media->ttlSeconds()),
MTPstring()); // query
};

View file

@ -121,6 +121,7 @@ MTPInputMedia PrepareUploadedDocument(
ComposeSendingDocumentAttributes(document),
MTP_vector<MTPInputDocument>(
ranges::to<QVector<MTPInputDocument>>(info.attachedStickers)),
MTPInputPhoto(), // video_cover
MTP_int(ttlSeconds));
}

View file

@ -272,6 +272,7 @@ void SendExistingDocument(
return MTP_inputMediaDocument(
MTP_flags(0),
document->mtpInput(),
MTPInputPhoto(), // video_cover
MTPint(), // ttl_seconds
MTPstring()); // query
};
@ -550,6 +551,7 @@ void SendConfirmedFile(
| (file->spoiler ? Flag::f_spoiler : Flag())),
file->document,
MTPVector<MTPDocument>(), // alt_documents
MTPPhoto(), // video_cover
MTPint());
} else if (file->type == SendMediaType::Audio) {
const auto ttlSeconds = file->to.options.ttlSeconds;
@ -560,6 +562,7 @@ void SendConfirmedFile(
| (ttlSeconds ? Flag::f_ttl_seconds : Flag())),
file->document,
MTPVector<MTPDocument>(), // alt_documents
MTPPhoto(), // video_cover
MTP_int(ttlSeconds));
} else if (file->type == SendMediaType::Round) {
using Flag = MTPDmessageMediaDocument::Flag;
@ -571,6 +574,7 @@ void SendConfirmedFile(
| (file->spoiler ? Flag::f_spoiler : Flag())),
file->document,
MTPVector<MTPDocument>(), // alt_documents
MTPPhoto(), // video_cover
MTP_int(ttlSeconds));
} else {
Unexpected("Type in sendFilesConfirmed.");

View file

@ -4146,6 +4146,7 @@ void ApiWrap::uploadAlbumMedia(
fields.vid(),
fields.vaccess_hash(),
fields.vfile_reference()),
MTPInputPhoto(), // video_cover
MTP_int(data.vttl_seconds().value_or_empty()),
MTPstring()); // query
sendAlbumWithUploaded(item, groupId, media);

View file

@ -526,7 +526,7 @@ void LevelBadge::paintEvent(QPaintEvent *e) {
struct SetValues {
uint8 colorIndex = 0;
DocumentId backgroundEmojiId = 0;
DocumentId statusId = 0;
EmojiStatusId statusId;
TimeId statusUntil = 0;
bool statusChanged = false;
};
@ -808,7 +808,7 @@ int ColorSelector::resizeGetHeight(int newWidth) {
const auto state = right->lifetime().make_state<State>();
state->panel.someCustomChosen(
) | rpl::start_with_next([=](EmojiStatusPanel::CustomChosen chosen) {
emojiIdChosen(chosen.id);
emojiIdChosen(chosen.id.documentId);
}, raw->lifetime());
std::move(colorIndexValue) | rpl::start_with_next([=](uint8 index) {
@ -901,8 +901,8 @@ int ColorSelector::resizeGetHeight(int newWidth) {
not_null<Ui::RpWidget*> parent,
std::shared_ptr<ChatHelpers::Show> show,
not_null<ChannelData*> channel,
rpl::producer<DocumentId> statusIdValue,
Fn<void(DocumentId,TimeId)> statusIdChosen,
rpl::producer<EmojiStatusId> statusIdValue,
Fn<void(EmojiStatusId,TimeId)> statusIdChosen,
bool group) {
const auto button = ButtonStyleWithRightEmoji(
parent,
@ -924,20 +924,24 @@ int ColorSelector::resizeGetHeight(int newWidth) {
struct State {
EmojiStatusPanel panel;
std::unique_ptr<Ui::Text::CustomEmoji> emoji;
DocumentId statusId = 0;
EmojiStatusId statusId;
};
const auto state = right->lifetime().make_state<State>();
state->panel.someCustomChosen(
) | rpl::start_with_next([=](EmojiStatusPanel::CustomChosen chosen) {
statusIdChosen(chosen.id, chosen.until);
statusIdChosen({ chosen.id }, chosen.until);
}, raw->lifetime());
const auto session = &show->session();
std::move(statusIdValue) | rpl::start_with_next([=](DocumentId id) {
std::move(statusIdValue) | rpl::start_with_next([=](EmojiStatusId id) {
state->statusId = id;
state->emoji = id
state->emoji = id.collectible // todo collectibles
? session->data().customEmojiManager().create(
id,
id.collectible->documentId,
[=] { right->update(); })
: id.documentId
? session->data().customEmojiManager().create(
id.documentId,
[=] { right->update(); })
: nullptr;
right->resize(
@ -990,7 +994,7 @@ int ColorSelector::resizeGetHeight(int newWidth) {
state->panel.show({
.controller = controller,
.button = right,
.ensureAddedEmojiId = state->statusId,
.ensureAddedEmojiId = state->statusId.documentId,
.channelStatusMode = true,
});
}
@ -1182,7 +1186,7 @@ void EditPeerColorBox(
struct State {
rpl::variable<uint8> index;
rpl::variable<DocumentId> emojiId;
rpl::variable<DocumentId> statusId;
rpl::variable<EmojiStatusId> statusId;
TimeId statusUntil = 0;
bool statusChanged = false;
bool changing = false;
@ -1319,7 +1323,7 @@ void EditPeerColorBox(
show,
channel,
state->statusId.value(),
[=](DocumentId id, TimeId until) {
[=](EmojiStatusId id, TimeId until) {
state->statusId = id;
state->statusUntil = until;
state->statusChanged = true;

View file

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/data_session.h"
#include "data/data_document.h"
#include "data/data_wall_paper.h"
#include "data/stickers/data_stickers.h"
#include "base/unixtime.h"
#include "base/timer_rpl.h"
@ -26,20 +27,19 @@ constexpr auto kRefreshDefaultListEach = 60 * 60 * crl::time(1000);
constexpr auto kRecentRequestTimeout = 10 * crl::time(1000);
constexpr auto kMaxTimeout = 6 * 60 * 60 * crl::time(1000);
[[nodiscard]] std::vector<DocumentId> ListFromMTP(
const MTPDaccount_emojiStatuses &data) {
const auto &list = data.vstatuses().v;
auto result = std::vector<DocumentId>();
result.reserve(list.size());
for (const auto &status : list) {
const auto parsed = ParseEmojiStatus(status);
if (!parsed.id) {
LOG(("API Error: emojiStatusEmpty in account.emojiStatuses."));
} else {
result.push_back(parsed.id);
}
}
return result;
[[nodiscard]] EmojiStatusCollectible ParseEmojiStatusCollectible(
const MTPDemojiStatusCollectible &data) {
return EmojiStatusCollectible{
.id = data.vcollectible_id().v,
.documentId = data.vdocument_id().v,
.title = qs(data.vtitle()),
.slug = qs(data.vslug()),
.patternDocumentId = data.vpattern_document_id().v,
.centerColor = Ui::ColorFromSerialized(data.vcenter_color()),
.edgeColor = Ui::ColorFromSerialized(data.vedge_color()),
.patternColor = Ui::ColorFromSerialized(data.vpattern_color()),
.textColor = Ui::ColorFromSerialized(data.vtext_color()),
};
}
} // namespace
@ -96,7 +96,7 @@ void EmojiStatuses::refreshRecentDelayed() {
});
}
const std::vector<DocumentId> &EmojiStatuses::list(Type type) const {
const std::vector<EmojiStatusId> &EmojiStatuses::list(Type type) const {
switch (type) {
case Type::Recent: return _recent;
case Type::Default: return _default;
@ -107,6 +107,30 @@ const std::vector<DocumentId> &EmojiStatuses::list(Type type) const {
Unexpected("Type in EmojiStatuses::list.");
}
EmojiStatusData EmojiStatuses::parse(const MTPEmojiStatus &status) {
return status.match([](const MTPDemojiStatus &data) {
return EmojiStatusData{
.id = { .documentId = data.vdocument_id().v },
.until = data.vuntil().value_or_empty(),
};
}, [&](const MTPDemojiStatusCollectible &data) {
const auto collectibleId = data.vcollectible_id().v;
auto &collectible = _collectibleData[collectibleId];
if (!collectible) {
collectible = std::make_shared<EmojiStatusCollectible>(
ParseEmojiStatusCollectible(data));
}
return EmojiStatusData{
.id = { .collectible = collectible },
.until = data.vuntil().value_or_empty(),
};
}, [](const MTPDinputEmojiStatusCollectible &) {
return EmojiStatusData();
}, [](const MTPDemojiStatusEmpty &) {
return EmojiStatusData();
});
}
rpl::producer<> EmojiStatuses::recentUpdates() const {
return _recentUpdated.events();
}
@ -119,6 +143,10 @@ rpl::producer<> EmojiStatuses::channelDefaultUpdates() const {
return _channelDefaultUpdated.events();
}
rpl::producer<> EmojiStatuses::collectiblesUpdates() const {
return _collectiblesUpdated.events();
}
void EmojiStatuses::registerAutomaticClear(
not_null<PeerData*> peer,
TimeId until) {
@ -253,7 +281,7 @@ void EmojiStatuses::processClearing() {
}
++i;
} else {
i->first->setEmojiStatus(0, 0);
i->first->setEmojiStatus(EmojiStatusId());
i = clearing.erase(i);
}
}
@ -271,6 +299,22 @@ void EmojiStatuses::processClearing() {
}
}
std::vector<EmojiStatusId> EmojiStatuses::parse(
const MTPDaccount_emojiStatuses &data) {
const auto &list = data.vstatuses().v;
auto result = std::vector<EmojiStatusId>();
result.reserve(list.size());
for (const auto &status : list) {
const auto parsed = parse(status);
if (!parsed.id) {
LOG(("API Error: empty status in account.emojiStatuses."));
} else {
result.push_back(parsed.id);
}
}
return result;
}
void EmojiStatuses::processClearingIn(TimeId wait) {
const auto waitms = wait * crl::time(1000);
_clearingTimer.callOnce(std::min(waitms, kMaxTimeout));
@ -376,13 +420,13 @@ void EmojiStatuses::requestChannelColored() {
void EmojiStatuses::updateRecent(const MTPDaccount_emojiStatuses &data) {
_recentHash = data.vhash().v;
_recent = ListFromMTP(data);
_recent = parse(data);
_recentUpdated.fire({});
}
void EmojiStatuses::updateDefault(const MTPDaccount_emojiStatuses &data) {
_defaultHash = data.vhash().v;
_default = ListFromMTP(data);
_default = parse(data);
_defaultUpdated.fire({});
}
@ -391,7 +435,9 @@ void EmojiStatuses::updateColored(const MTPDmessages_stickerSet &data) {
_colored.clear();
_colored.reserve(list.size());
for (const auto &sticker : data.vdocuments().v) {
_colored.push_back(_owner->processDocument(sticker)->id);
_colored.push_back({
.documentId = _owner->processDocument(sticker)->id,
});
}
_coloredUpdated.fire({});
}
@ -399,7 +445,7 @@ void EmojiStatuses::updateColored(const MTPDmessages_stickerSet &data) {
void EmojiStatuses::updateChannelDefault(
const MTPDaccount_emojiStatuses &data) {
_channelDefaultHash = data.vhash().v;
_channelDefault = ListFromMTP(data);
_channelDefault = parse(data);
_channelDefaultUpdated.fire({});
}
@ -409,18 +455,20 @@ void EmojiStatuses::updateChannelColored(
_channelColored.clear();
_channelColored.reserve(list.size());
for (const auto &sticker : data.vdocuments().v) {
_channelColored.push_back(_owner->processDocument(sticker)->id);
_channelColored.push_back({
.documentId = _owner->processDocument(sticker)->id,
});
}
_channelColoredUpdated.fire({});
}
void EmojiStatuses::set(DocumentId id, TimeId until) {
void EmojiStatuses::set(EmojiStatusId id, TimeId until) {
set(_owner->session().user(), id, until);
}
void EmojiStatuses::set(
not_null<PeerData*> peer,
DocumentId id,
EmojiStatusId id,
TimeId until) {
auto &api = _owner->session().api();
auto &requestId = _sentRequests[peer];
@ -437,11 +485,19 @@ void EmojiStatuses::set(
_sentRequests.remove(peer);
}).send();
};
using EFlag = MTPDemojiStatus::Flag;
using CFlag = MTPDinputEmojiStatusCollectible::Flag;
const auto status = !id
? MTP_emojiStatusEmpty()
: !until
? MTP_emojiStatus(MTP_long(id))
: MTP_emojiStatusUntil(MTP_long(id), MTP_int(until));
: id.collectible
? MTP_inputEmojiStatusCollectible(
MTP_flags(until ? CFlag::f_until : CFlag()),
MTP_long(id.collectible->id),
MTP_int(until))
: MTP_emojiStatus(
MTP_flags(until ? EFlag::f_until : EFlag()),
MTP_long(id.documentId),
MTP_int(until));
if (peer->isSelf()) {
send(MTPaccount_UpdateEmojiStatus(status));
} else if (const auto channel = peer->asChannel()) {
@ -449,14 +505,4 @@ void EmojiStatuses::set(
}
}
EmojiStatusData ParseEmojiStatus(const MTPEmojiStatus &status) {
return status.match([](const MTPDemojiStatus &data) {
return EmojiStatusData{ data.vdocument_id().v };
}, [](const MTPDemojiStatusUntil &data) {
return EmojiStatusData{ data.vdocument_id().v, data.vuntil().v };
}, [](const MTPDemojiStatusEmpty &) {
return EmojiStatusData();
});
}
} // namespace Data

View file

@ -22,6 +22,26 @@ namespace Data {
class DocumentMedia;
class Session;
struct EmojiStatusCollectible {
CollectibleId id = 0;
DocumentId documentId = 0;
QString title;
QString slug;
DocumentId patternDocumentId = 0;
QColor centerColor;
QColor edgeColor;
QColor patternColor;
QColor textColor;
explicit operator bool() const {
return id != 0;
}
};
struct EmojiStatusData {
EmojiStatusId id;
TimeId until = 0;
};
class EmojiStatuses final {
public:
explicit EmojiStatuses(not_null<Session*> owner);
@ -45,15 +65,19 @@ public:
Colored,
ChannelDefault,
ChannelColored,
Collectibles,
};
[[nodiscard]] const std::vector<DocumentId> &list(Type type) const;
[[nodiscard]] const std::vector<EmojiStatusId> &list(Type type) const;
[[nodiscard]] EmojiStatusData parse(const MTPEmojiStatus &status);
[[nodiscard]] rpl::producer<> recentUpdates() const;
[[nodiscard]] rpl::producer<> defaultUpdates() const;
[[nodiscard]] rpl::producer<> channelDefaultUpdates() const;
[[nodiscard]] rpl::producer<> collectiblesUpdates() const;
void set(DocumentId id, TimeId until = 0);
void set(not_null<PeerData*> peer, DocumentId id, TimeId until = 0);
void set(EmojiStatusId id, TimeId until = 0);
void set(not_null<PeerData*> peer, EmojiStatusId id, TimeId until = 0);
void registerAutomaticClear(not_null<PeerData*> peer, TimeId until);
@ -89,21 +113,30 @@ private:
void processClearingIn(TimeId wait);
void processClearing();
[[nodiscard]] std::vector<EmojiStatusId> parse(
const MTPDaccount_emojiStatuses &data);
template <typename Request>
void requestGroups(not_null<GroupsType*> type, Request &&request);
const not_null<Session*> _owner;
std::vector<DocumentId> _recent;
std::vector<DocumentId> _default;
std::vector<DocumentId> _colored;
std::vector<DocumentId> _channelDefault;
std::vector<DocumentId> _channelColored;
std::vector<EmojiStatusId> _recent;
std::vector<EmojiStatusId> _default;
std::vector<EmojiStatusId> _colored;
std::vector<EmojiStatusId> _channelDefault;
std::vector<EmojiStatusId> _channelColored;
std::vector<EmojiStatusId> _collectibles;
rpl::event_stream<> _recentUpdated;
rpl::event_stream<> _defaultUpdated;
rpl::event_stream<> _coloredUpdated;
rpl::event_stream<> _channelDefaultUpdated;
rpl::event_stream<> _channelColoredUpdated;
rpl::event_stream<> _collectiblesUpdated;
base::flat_map<
CollectibleId,
std::shared_ptr<EmojiStatusCollectible>> _collectibleData;
mtpRequestId _recentRequestId = 0;
bool _recentRequestScheduled = false;
@ -119,6 +152,8 @@ private:
mtpRequestId _channelColoredRequestId = 0;
mtpRequestId _collectiblesRequestId = 0;
base::flat_map<not_null<PeerData*>, mtpRequestId> _sentRequests;
base::flat_map<not_null<PeerData*>, TimeId> _clearing;
@ -133,10 +168,4 @@ private:
};
struct EmojiStatusData {
DocumentId id = 0;
TimeId until = 0;
};
[[nodiscard]] EmojiStatusData ParseEmojiStatus(const MTPEmojiStatus &status);
} // namespace Data

View file

@ -1115,11 +1115,11 @@ bool PeerData::changeBackgroundEmojiId(DocumentId id) {
}
void PeerData::setEmojiStatus(const MTPEmojiStatus &status) {
const auto parsed = Data::ParseEmojiStatus(status);
const auto parsed = owner().emojiStatuses().parse(status);
setEmojiStatus(parsed.id, parsed.until);
}
void PeerData::setEmojiStatus(DocumentId emojiStatusId, TimeId until) {
void PeerData::setEmojiStatus(EmojiStatusId emojiStatusId, TimeId until) {
if (_emojiStatusId != emojiStatusId) {
_emojiStatusId = emojiStatusId;
session().changes().peerUpdated(this, UpdateFlag::EmojiStatus);
@ -1127,7 +1127,7 @@ void PeerData::setEmojiStatus(DocumentId emojiStatusId, TimeId until) {
owner().emojiStatuses().registerAutomaticClear(this, until);
}
DocumentId PeerData::emojiStatusId() const {
EmojiStatusId PeerData::emojiStatusId() const {
return _emojiStatusId;
}

View file

@ -206,8 +206,8 @@ public:
bool changeBackgroundEmojiId(DocumentId id);
void setEmojiStatus(const MTPEmojiStatus &status);
void setEmojiStatus(DocumentId emojiStatusId, TimeId until = 0);
[[nodiscard]] DocumentId emojiStatusId() const;
void setEmojiStatus(EmojiStatusId emojiStatusId, TimeId until = 0);
[[nodiscard]] EmojiStatusId emojiStatusId() const;
[[nodiscard]] bool isUser() const {
return peerIsUser(id);
@ -523,7 +523,7 @@ private:
base::flat_set<QString> _nameWords; // for filtering
base::flat_set<QChar> _nameFirstLetters;
DocumentId _emojiStatusId = 0;
EmojiStatusId _emojiStatusId;
DocumentId _backgroundEmojiId = 0;
crl::time _lastFullUpdate = 0;

View file

@ -695,7 +695,7 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
if (const auto &status = data.vemoji_status()) {
result->setEmojiStatus(*status);
} else {
result->setEmojiStatus(0);
result->setEmojiStatus(EmojiStatusId());
}
if (!minimal) {
if (const auto botInfoVersion = data.vbot_info_version()) {
@ -886,7 +886,7 @@ not_null<PeerData*> Session::processChat(const MTPChat &data) {
if (const auto &status = data.vemoji_status()) {
channel->setEmojiStatus(*status);
} else {
channel->setEmojiStatus(0);
channel->setEmojiStatus(EmojiStatusId());
}
if (minimal) {
if (channel->input.type() == mtpc_inputPeerEmpty

View file

@ -37,6 +37,7 @@ using Options = base::flags<Option>;
namespace Data {
struct FileOrigin;
struct EmojiStatusCollectible;
struct UploadState {
explicit UploadState(int64 size) : size(size) {
@ -139,6 +140,23 @@ using WallPaperId = uint64;
using CallId = uint64;
using BotAppId = uint64;
using EffectId = uint64;
using CollectibleId = uint64;
struct EmojiStatusId {
DocumentId documentId = 0;
std::shared_ptr<Data::EmojiStatusCollectible> collectible;
explicit operator bool() const {
return documentId || collectible;
}
friend inline auto operator<=>(
const EmojiStatusId &,
const EmojiStatusId &) = default;
friend inline bool operator==(
const EmojiStatusId &,
const EmojiStatusId &) = default;
};
constexpr auto CancelledWebPageId = WebPageId(0xFFFFFFFFFFFFFFFFULL);

View file

@ -2003,17 +2003,19 @@ void GenerateItems(
return status.match([](
const MTPDemojiStatus &data) {
return data.vdocument_id().v;
}, [](const MTPDemojiStatusCollectible &data) {
return data.vdocument_id().v;
}, [](const MTPDemojiStatusEmpty &) {
return DocumentId();
}, [](const MTPDemojiStatusUntil &data) {
return data.vdocument_id().v;
}, [](const MTPDinputEmojiStatusCollectible &) {
return DocumentId();
});
};
const auto prevEmoji = parse(data.vprev_value());
const auto nextEmoji = parse(data.vnew_value());
const auto nextUntil = data.vnew_value().match([](
const MTPDemojiStatusUntil &data) {
return data.vuntil().v;
const MTPDemojiStatus &data) {
return TimeId(data.vuntil().value_or_empty());
}, [](const auto &) { return TimeId(); });
const auto text = !prevEmoji

View file

@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/ui_integration.h"
#include "data/business/data_business_chatbots.h"
#include "data/notify/data_notify_settings.h"
#include "data/data_emoji_statuses.h"
#include "data/data_peer.h"
#include "data/data_user.h"
#include "data/data_chat.h"
@ -112,8 +113,11 @@ namespace {
Data::PeerUpdate::Flag::EmojiStatus
) | rpl::map([=] {
const auto id = peer->emojiStatusId();
return id
? ResolveIsCustom(owner, id)
const auto documentId = id.collectible
? id.collectible->documentId
: id.documentId;
return documentId
? ResolveIsCustom(owner, documentId)
: rpl::single(TextWithEntities());
}) | rpl::flatten_latest() | rpl::distinct_until_changed();
}

View file

@ -1767,8 +1767,8 @@ void Message::paintFromName(
+ std::min(availableWidth - statusWidth, nameText->maxWidth());
const auto y = trect.top();
auto color = nameFg;
color.setAlpha(115);
const auto id = from ? from->emojiStatusId() : 0;
color.setAlpha(115); // todo collectibles
const auto id = from ? from->emojiStatusId().documentId : 0;
if (_fromNameStatus->id != id) {
const auto that = const_cast<Message*>(this);
_fromNameStatus->custom = id

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "info/profile/info_profile_badge.h"
#include "data/data_emoji_statuses.h"
#include "data/data_peer.h"
#include "data/data_session.h"
#include "data/data_user.h"
@ -29,9 +30,9 @@ namespace {
return rpl::combine(
BadgeValue(peer),
EmojiStatusIdValue(peer)
) | rpl::map([=](BadgeType badge, DocumentId emojiStatusId) {
) | rpl::map([=](BadgeType badge, EmojiStatusId emojiStatusId) {
if (statusOnlyForPremium && badge != BadgeType::Premium) {
emojiStatusId = 0;
emojiStatusId = EmojiStatusId();
} else if (emojiStatusId && badge == BadgeType::None) {
badge = BadgeType::Premium;
}
@ -129,9 +130,12 @@ void Badge::setContent(Content content) {
: id
? nullptr
: &_st.premium;
if (id) {
const auto documentId = id.collectible
? id.collectible->documentId
: id.documentId;
if (documentId) {
_emojiStatus = _session->data().customEmojiManager().create(
id,
documentId,
[raw = _view.data()] { raw->update(); },
sizeTag());
if (_customStatusLoopsLimit > 0) {

View file

@ -59,7 +59,7 @@ public:
struct Content {
BadgeType badge = BadgeType::None;
DocumentId emojiStatusId = 0;
EmojiStatusId emojiStatusId;
friend inline constexpr bool operator==(Content, Content) = default;
};

View file

@ -111,18 +111,28 @@ void EmojiStatusPanel::show(Descriptor &&descriptor) {
_panelButton = button;
_animationSizeTag = descriptor.animationSizeTag;
const auto feed = [=, now = descriptor.ensureAddedEmojiId](
std::vector<DocumentId> list) {
list.insert(begin(list), 0);
std::vector<EmojiStatusId> list) {
list.insert(begin(list), EmojiStatusId());
if (now && !ranges::contains(list, now)) {
list.push_back(now);
}
_panel->selector()->provideRecentEmoji(list);
auto tmp = std::vector<DocumentId>();
for (const auto &id : list) {
if (id.documentId) { // todo collectibles
tmp.push_back(id.documentId);
}
}
_panel->selector()->provideRecentEmoji(tmp);
};
if (descriptor.backgroundEmojiMode) {
controller->session().api().peerPhoto().emojiListValue(
Api::PeerPhoto::EmojiListType::Background
) | rpl::start_with_next([=](std::vector<DocumentId> &&list) {
feed(std::move(list));
auto tmp = std::vector<EmojiStatusId>();
for (const auto &id : list) { // todo collectibles
tmp.push_back(EmojiStatusId{ .documentId = id });
}
feed(std::move(tmp));
}, _panel->lifetime());
} else if (descriptor.channelStatusMode) {
const auto &statuses = controller->session().data().emojiStatuses();
@ -254,8 +264,8 @@ void EmojiStatusPanel::create(const Descriptor &descriptor) {
) | rpl::start_with_next([=](const Chosen &chosen) {
const auto owner = &controller->session().data();
startAnimation(owner, body, chosen.id, chosen.animation);
_someCustomChosen.fire({ chosen.id, chosen.until });
_panel->hideAnimated();
_someCustomChosen.fire({ { chosen.id }, chosen.until });
_panel->hideAnimated(); // todo collectibles
}, _panel->lifetime());
} else {
const auto weak = Ui::MakeWeak(_panel.get());
@ -266,8 +276,8 @@ void EmojiStatusPanel::create(const Descriptor &descriptor) {
const auto owner = &controller->session().data();
if (weak) {
startAnimation(owner, body, chosen.id, chosen.animation);
}
owner->emojiStatuses().set(chosen.id, chosen.until);
} // todo collectibles
owner->emojiStatuses().set({ chosen.id }, chosen.until);
};
rpl::merge(

View file

@ -52,7 +52,7 @@ public:
not_null<Window::SessionController*> controller;
not_null<QWidget*> button;
Data::CustomEmojiSizeTag animationSizeTag = {};
DocumentId ensureAddedEmojiId = 0;
EmojiStatusId ensureAddedEmojiId;
Fn<QColor()> customTextColor;
bool backgroundEmojiMode = false;
bool channelStatusMode = false;
@ -61,7 +61,7 @@ public:
void repaint();
struct CustomChosen {
DocumentId id = 0;
EmojiStatusId id;
TimeId until = 0;
};
[[nodiscard]] rpl::producer<CustomChosen> someCustomChosen() const {

View file

@ -676,9 +676,9 @@ rpl::producer<BadgeType> BadgeValue(not_null<PeerData*> peer) {
return rpl::single(BadgeType::None);
}
rpl::producer<DocumentId> EmojiStatusIdValue(not_null<PeerData*> peer) {
rpl::producer<EmojiStatusId> EmojiStatusIdValue(not_null<PeerData*> peer) {
if (peer->isChat()) {
return rpl::single(DocumentId(0));
return rpl::single(EmojiStatusId());
}
return peer->session().changes().peerFlagsValue(
peer,

View file

@ -132,7 +132,7 @@ struct LinkWithUrl {
enum class BadgeType;
[[nodiscard]] rpl::producer<BadgeType> BadgeValue(not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<DocumentId> EmojiStatusIdValue(
[[nodiscard]] rpl::producer<EmojiStatusId> EmojiStatusIdValue(
not_null<PeerData*> peer);
[[nodiscard]] rpl::producer<QString> BirthdayLabelText(

View file

@ -590,7 +590,7 @@ void ConfirmEmojiStatusBox(
return;
}
document->owner().emojiStatuses().set(
document->id,
{ document->id },
duration ? (base::unixtime::now() + duration) : 0);
*set = true;
box->closeBox();

View file

@ -33,8 +33,8 @@ inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile sti
inputMediaPhoto#b3ba0635 flags:# spoiler:flags.1?true id:InputPhoto ttl_seconds:flags.0?int = InputMedia;
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia;
inputMediaUploadedDocument#5b38c6c1 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> ttl_seconds:flags.1?int = InputMedia;
inputMediaDocument#33473058 flags:# spoiler:flags.2?true id:InputDocument ttl_seconds:flags.0?int query:flags.1?string = InputMedia;
inputMediaUploadedDocument#f041c42d flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector<DocumentAttribute> stickers:flags.0?Vector<InputDocument> video_cover:flags.6?InputPhoto ttl_seconds:flags.1?int = InputMedia;
inputMediaDocument#74067321 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto ttl_seconds:flags.0?int query:flags.1?string = InputMedia;
inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia;
inputMediaDocumentExternal#fb52dc99 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia;
@ -124,7 +124,7 @@ messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia;
messageMediaUnsupported#9f84f49e = MessageMedia;
messageMediaDocument#dd570bd5 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector<Document> ttl_seconds:flags.2?int = MessageMedia;
messageMediaDocument#dbbdf614 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector<Document> video_cover:flags.9?Photo ttl_seconds:flags.2?int = MessageMedia;
messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia;
messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia;
messageMediaGame#fdb19008 game:Game = MessageMedia;
@ -1498,8 +1498,9 @@ premiumGiftOption#74c34319 flags:# months:int currency:string amount:long bot_ur
paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod;
emojiStatusEmpty#2de11aae = EmojiStatus;
emojiStatus#929b619d document_id:long = EmojiStatus;
emojiStatusUntil#fa30a8c7 document_id:long until:int = EmojiStatus;
emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus;
emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus;
inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus;
account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses;
account.emojiStatuses#90c467d1 hash:long statuses:Vector<EmojiStatus> = account.EmojiStatuses;
@ -2077,6 +2078,7 @@ account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool;
account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool;
account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings;
account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings;
account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses;
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
@ -2639,4 +2641,4 @@ smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool;
fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;
// LAYER 197
// LAYER 198

View file

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/ui_integration.h" // MarkedTextContext.
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_emoji_statuses.h"
#include "data/data_peer_values.h"
#include "data/data_session.h"
#include "data/stickers/data_custom_emoji.h" // SerializeCustomEmojiId.
@ -606,9 +607,12 @@ TopBarUser::TopBarUser(
auto documentValue = Info::Profile::EmojiStatusIdValue(
peer
) | rpl::map([=](DocumentId id) -> DocumentData* {
const auto document = id
? controller->session().data().document(id).get()
) | rpl::map([=](EmojiStatusId id) -> DocumentData* {
const auto documentId = id.collectible
? id.collectible->documentId
: id.documentId;
const auto document = documentId
? controller->session().data().document(documentId).get()
: nullptr;
return (document && document->sticker()) ? document : nullptr;
});
@ -1184,7 +1188,7 @@ QPointer<Ui::RpWidget> Premium::createPinnedToBottom(
if (const auto peer = data.peer(emojiStatusData.peerId)) {
return Info::Profile::EmojiStatusIdValue(
peer
) | rpl::map([=](DocumentId id) {
) | rpl::map([=](EmojiStatusId id) {
return id
? tr::lng_premium_emoji_status_button()
: _buttonText.value();

View file

@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "ui/unread_badge.h"
#include "data/data_emoji_statuses.h"
#include "data/data_peer.h"
#include "data/data_user.h"
#include "data/data_session.h"
@ -26,7 +27,7 @@ constexpr auto kPlayStatusLimit = 2;
} // namespace
struct PeerBadge::EmojiStatus {
DocumentId id = 0;
EmojiStatusId id;
std::unique_ptr<Ui::Text::CustomEmoji> emoji;
int skip = 0;
};
@ -238,11 +239,17 @@ int PeerBadge::drawPremiumEmojiStatus(
using namespace Ui::Text;
auto &manager = peer->session().data().customEmojiManager();
_emojiStatus->id = id;
_emojiStatus->emoji = std::make_unique<LimitedLoopsEmoji>(
manager.create(
id,
descriptor.customEmojiRepaint),
kPlayStatusLimit);
_emojiStatus->emoji = id.collectible // todo collectibles
? std::make_unique<LimitedLoopsEmoji>(
manager.create(
id.collectible->documentId,
descriptor.customEmojiRepaint),
kPlayStatusLimit)
: std::make_unique<LimitedLoopsEmoji>(
manager.create(
id.documentId,
descriptor.customEmojiRepaint),
kPlayStatusLimit);
}
_emojiStatus->emoji->paint(p, {
.textColor = (*descriptor.premiumFg)->c,

View file

@ -179,7 +179,7 @@ void ShowCallsBox(not_null<Window::SessionController*> window) {
self,
Data::PeerUpdate::Flag::EmojiStatus
) | rpl::map([=] {
return (self->emojiStatusId() != 0);
return !!self->emojiStatusId();
}) | rpl::distinct_until_changed() | rpl::map([](bool has) {
const auto makeLink = [](const QString &text) {
return Ui::Text::Link(text);