Show chat intro in an empty chat.

This commit is contained in:
John Preston 2024-03-21 12:03:02 +04:00
parent 7f4d13c54a
commit 85554d19e4
12 changed files with 194 additions and 293 deletions

View file

@ -2302,7 +2302,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_chat_intro_title" = "Intro";
"lng_chat_intro_subtitle" = "Customize your intro";
"lng_chat_intro_default_title" = "No messages here yet...";
"lng_chat_intro_default_message" = "Send a message or tap on the greeting below";
"lng_chat_intro_default_message" = "Send a message or click on the greeting below";
"lng_chat_intro_enter_title" = "Enter Title";
"lng_chat_intro_enter_message" = "Enter Message";
"lng_chat_intro_choose_sticker" = "Choose Sticker";

View file

@ -153,8 +153,10 @@ BusinessRecipients FromMTP(
}
BusinessDetails FromMTP(
not_null<Session*> owner,
const tl::conditional<MTPBusinessWorkHours> &hours,
const tl::conditional<MTPBusinessLocation> &location) {
const tl::conditional<MTPBusinessLocation> &location,
const tl::conditional<MTPBusinessIntro> &intro) {
auto result = BusinessDetails();
if (hours) {
const auto &data = hours->data();
@ -179,6 +181,17 @@ BusinessDetails FromMTP(
});
}
}
if (intro) {
const auto &data = intro->data();
result.intro.title = qs(data.vtitle());
result.intro.description = qs(data.vdescription());
if (const auto document = data.vsticker()) {
result.intro.sticker = owner->processDocument(*document);
if (!result.intro.sticker->sticker()) {
result.intro.sticker = nullptr;
}
}
}
return result;
}
@ -334,22 +347,4 @@ WorkingIntervals ReplaceDayIntervals(
return result.normalized();
}
ChatIntro FromMTP(
not_null<Session*> owner,
const tl::conditional<MTPBusinessIntro> &intro) {
auto result = ChatIntro();
if (intro) {
const auto &data = intro->data();
result.title = qs(data.vtitle());
result.description = qs(data.vdescription());
if (const auto document = data.vsticker()) {
result.sticker = owner->processDocument(*document);
if (!result.sticker->sticker()) {
result.sticker = nullptr;
}
}
}
return result;
}
} // namespace Data

View file

@ -182,12 +182,27 @@ struct BusinessLocation {
const BusinessLocation &b) = default;
};
struct ChatIntro {
QString title;
QString description;
DocumentData *sticker = nullptr;
explicit operator bool() const {
return !title.isEmpty() || !description.isEmpty();
}
friend inline bool operator==(
const ChatIntro &a,
const ChatIntro &b) = default;
};
struct BusinessDetails {
WorkingHours hours;
BusinessLocation location;
ChatIntro intro;
explicit operator bool() const {
return hours || location;
return hours || location || intro;
}
friend inline bool operator==(
@ -196,8 +211,10 @@ struct BusinessDetails {
};
[[nodiscard]] BusinessDetails FromMTP(
not_null<Session*> owner,
const tl::conditional<MTPBusinessWorkHours> &hours,
const tl::conditional<MTPBusinessLocation> &location);
const tl::conditional<MTPBusinessLocation> &location,
const tl::conditional<MTPBusinessIntro> &intro);
enum class AwayScheduleType : uchar {
Never = 0,
@ -252,22 +269,4 @@ struct GreetingSettings {
not_null<Session*> owner,
const tl::conditional<MTPBusinessGreetingMessage> &message);
struct ChatIntro {
QString title;
QString description;
DocumentData *sticker = nullptr;
explicit operator bool() const {
return !title.isEmpty() || !description.isEmpty();
}
friend inline bool operator==(
const ChatIntro &a,
const ChatIntro &b) = default;
};
[[nodiscard]] ChatIntro FromMTP(
not_null<Session*> owner,
const tl::conditional<MTPBusinessIntro> &intro);
} // namespace Data

View file

@ -96,6 +96,40 @@ void BusinessInfo::saveWorkingHours(
session->user()->setBusinessDetails(std::move(details));
}
void BusinessInfo::saveChatIntro(ChatIntro data, Fn<void(QString)> fail) {
const auto session = &_owner->session();
auto details = session->user()->businessDetails();
const auto &was = details.intro;
if (was == data) {
return;
} else {
const auto session = &_owner->session();
using Flag = MTPaccount_UpdateBusinessIntro::Flag;
session->api().request(MTPaccount_UpdateBusinessIntro(
MTP_flags(data ? Flag::f_intro : Flag()),
MTP_inputBusinessIntro(
MTP_flags(data.sticker
? MTPDinputBusinessIntro::Flag::f_sticker
: MTPDinputBusinessIntro::Flag()),
MTP_string(data.title),
MTP_string(data.description),
(data.sticker
? data.sticker->mtpInput()
: MTP_inputDocumentEmpty()))
)).fail([=](const MTP::Error &error) {
auto details = session->user()->businessDetails();
details.intro = was;
session->user()->setBusinessDetails(std::move(details));
if (fail) {
fail(error.type());
}
}).send();
}
details.intro = std::move(data);
session->user()->setBusinessDetails(std::move(details));
}
void BusinessInfo::applyAwaySettings(AwaySettings data) {
if (_awaySettings == data) {
return;
@ -184,54 +218,6 @@ rpl::producer<> BusinessInfo::greetingSettingsChanged() const {
return _greetingSettingsChanged.events();
}
void BusinessInfo::saveChatIntro(ChatIntro data, Fn<void(QString)> fail) {
const auto &was = _chatIntro;
if (was == data) {
return;
} else {
const auto session = &_owner->session();
using Flag = MTPaccount_UpdateBusinessIntro::Flag;
session->api().request(MTPaccount_UpdateBusinessIntro(
MTP_flags(data ? Flag::f_intro : Flag()),
MTP_inputBusinessIntro(
MTP_flags(data.sticker ? MTPDinputBusinessIntro::Flag::f_sticker : MTPDinputBusinessIntro::Flag()),
MTP_string(data.title),
MTP_string(data.description),
(data.sticker
? data.sticker->mtpInput()
: MTP_inputDocumentEmpty()))
)).fail([=](const MTP::Error &error) {
_chatIntro = was;
_chatIntroChanged.fire({});
if (fail) {
fail(error.type());
}
}).send();
}
_chatIntro = std::move(data);
_chatIntroChanged.fire({});
}
void BusinessInfo::applyChatIntro(ChatIntro data) {
if (_chatIntro == data) {
return;
}
_chatIntro = data;
_chatIntroChanged.fire({});
}
ChatIntro BusinessInfo::chatIntro() const {
return _chatIntro.value_or(ChatIntro());
}
bool BusinessInfo::chatIntroLoaded() const {
return _chatIntro.has_value();
}
rpl::producer<> BusinessInfo::chatIntroChanged() const {
return _chatIntroChanged.events();
}
void BusinessInfo::preload() {
preloadTimezones();
}

View file

@ -21,6 +21,7 @@ public:
void preload();
void saveWorkingHours(WorkingHours data, Fn<void(QString)> fail);
void saveChatIntro(ChatIntro data, Fn<void(QString)> fail);
void saveAwaySettings(AwaySettings data, Fn<void(QString)> fail);
void applyAwaySettings(AwaySettings data);
@ -36,12 +37,6 @@ public:
[[nodiscard]] bool greetingSettingsLoaded() const;
[[nodiscard]] rpl::producer<> greetingSettingsChanged() const;
void saveChatIntro(ChatIntro data, Fn<void(QString)> fail);
void applyChatIntro(ChatIntro data);
[[nodiscard]] ChatIntro chatIntro() const;
[[nodiscard]] bool chatIntroLoaded() const;
[[nodiscard]] rpl::producer<> chatIntroChanged() const;
void preloadTimezones();
[[nodiscard]] bool timezonesLoaded() const;
[[nodiscard]] rpl::producer<Timezones> timezonesValue() const;
@ -57,9 +52,6 @@ private:
std::optional<GreetingSettings> _greetingSettings;
rpl::event_stream<> _greetingSettingsChanged;
std::optional<ChatIntro> _chatIntro;
rpl::event_stream<> _chatIntroChanged;
mtpRequestId _timezonesRequestId = 0;
int32 _timezonesHash = 0;

View file

@ -594,15 +594,15 @@ void ApplyUserUpdate(not_null<UserData*> user, const MTPDuserFull &update) {
}
user->setBusinessDetails(FromMTP(
&user->owner(),
update.vbusiness_work_hours(),
update.vbusiness_location()));
update.vbusiness_location(),
update.vbusiness_intro()));
if (user->isSelf()) {
user->owner().businessInfo().applyAwaySettings(
FromMTP(&user->owner(), update.vbusiness_away_message()));
user->owner().businessInfo().applyGreetingSettings(
FromMTP(&user->owner(), update.vbusiness_greeting_message()));
user->owner().businessInfo().applyChatIntro(
FromMTP(&user->owner(), update.vbusiness_intro()));
}
user->owner().stories().apply(user, update.vstories());

View file

@ -502,7 +502,7 @@ void Stickers::undoInstallLocally(uint64 setId) {
Ui::LayerOption::KeepOther);
}
bool Stickers::isFaved(not_null<const DocumentData*> document) {
bool Stickers::isFaved(not_null<const DocumentData*> document) const {
const auto &sets = this->sets();
const auto it = sets.find(FavedSetId);
if (it == sets.cend()) {

View file

@ -80,13 +80,13 @@ public:
void incrementSticker(not_null<DocumentData*> document);
bool updateNeeded(crl::time now) const {
[[nodiscard]] bool updateNeeded(crl::time now) const {
return updateNeeded(_lastUpdate, now);
}
void setLastUpdate(crl::time update) {
_lastUpdate = update;
}
bool recentUpdateNeeded(crl::time now) const {
[[nodiscard]] bool recentUpdateNeeded(crl::time now) const {
return updateNeeded(_lastRecentUpdate, now);
}
void setLastRecentUpdate(crl::time update) {
@ -95,19 +95,19 @@ public:
}
_lastRecentUpdate = update;
}
bool masksUpdateNeeded(crl::time now) const {
[[nodiscard]] bool masksUpdateNeeded(crl::time now) const {
return updateNeeded(_lastMasksUpdate, now);
}
void setLastMasksUpdate(crl::time update) {
_lastMasksUpdate = update;
}
bool emojiUpdateNeeded(crl::time now) const {
[[nodiscard]] bool emojiUpdateNeeded(crl::time now) const {
return updateNeeded(_lastEmojiUpdate, now);
}
void setLastEmojiUpdate(crl::time update) {
_lastEmojiUpdate = update;
}
bool recentAttachedUpdateNeeded(crl::time now) const {
[[nodiscard]] bool recentAttachedUpdateNeeded(crl::time now) const {
return updateNeeded(_lastRecentAttachedUpdate, now);
}
void setLastRecentAttachedUpdate(crl::time update) {
@ -116,31 +116,31 @@ public:
}
_lastRecentAttachedUpdate = update;
}
bool favedUpdateNeeded(crl::time now) const {
[[nodiscard]] bool favedUpdateNeeded(crl::time now) const {
return updateNeeded(_lastFavedUpdate, now);
}
void setLastFavedUpdate(crl::time update) {
_lastFavedUpdate = update;
}
bool featuredUpdateNeeded(crl::time now) const {
[[nodiscard]] bool featuredUpdateNeeded(crl::time now) const {
return updateNeeded(_lastFeaturedUpdate, now);
}
void setLastFeaturedUpdate(crl::time update) {
_lastFeaturedUpdate = update;
}
bool featuredEmojiUpdateNeeded(crl::time now) const {
[[nodiscard]] bool featuredEmojiUpdateNeeded(crl::time now) const {
return updateNeeded(_lastFeaturedEmojiUpdate, now);
}
void setLastFeaturedEmojiUpdate(crl::time update) {
_lastFeaturedEmojiUpdate = update;
}
bool savedGifsUpdateNeeded(crl::time now) const {
[[nodiscard]] bool savedGifsUpdateNeeded(crl::time now) const {
return updateNeeded(_lastSavedGifsUpdate, now);
}
void setLastSavedGifsUpdate(crl::time update) {
_lastSavedGifsUpdate = update;
}
int featuredSetsUnreadCount() const {
[[nodiscard]] int featuredSetsUnreadCount() const {
return _featuredSetsUnreadCount.current();
}
void setFeaturedSetsUnreadCount(int count) {
@ -149,58 +149,58 @@ public:
[[nodiscard]] rpl::producer<int> featuredSetsUnreadCountValue() const {
return _featuredSetsUnreadCount.value();
}
const StickersSets &sets() const {
[[nodiscard]] const StickersSets &sets() const {
return _sets;
}
StickersSets &setsRef() {
[[nodiscard]] StickersSets &setsRef() {
return _sets;
}
const StickersSetsOrder &setsOrder() const {
[[nodiscard]] const StickersSetsOrder &setsOrder() const {
return _setsOrder;
}
StickersSetsOrder &setsOrderRef() {
[[nodiscard]] StickersSetsOrder &setsOrderRef() {
return _setsOrder;
}
const StickersSetsOrder &maskSetsOrder() const {
[[nodiscard]] const StickersSetsOrder &maskSetsOrder() const {
return _maskSetsOrder;
}
StickersSetsOrder &maskSetsOrderRef() {
[[nodiscard]] StickersSetsOrder &maskSetsOrderRef() {
return _maskSetsOrder;
}
const StickersSetsOrder &emojiSetsOrder() const {
[[nodiscard]] const StickersSetsOrder &emojiSetsOrder() const {
return _emojiSetsOrder;
}
StickersSetsOrder &emojiSetsOrderRef() {
[[nodiscard]] StickersSetsOrder &emojiSetsOrderRef() {
return _emojiSetsOrder;
}
const StickersSetsOrder &featuredSetsOrder() const {
[[nodiscard]] const StickersSetsOrder &featuredSetsOrder() const {
return _featuredSetsOrder;
}
StickersSetsOrder &featuredSetsOrderRef() {
[[nodiscard]] StickersSetsOrder &featuredSetsOrderRef() {
return _featuredSetsOrder;
}
const StickersSetsOrder &featuredEmojiSetsOrder() const {
[[nodiscard]] const StickersSetsOrder &featuredEmojiSetsOrder() const {
return _featuredEmojiSetsOrder;
}
StickersSetsOrder &featuredEmojiSetsOrderRef() {
[[nodiscard]] StickersSetsOrder &featuredEmojiSetsOrderRef() {
return _featuredEmojiSetsOrder;
}
const StickersSetsOrder &archivedSetsOrder() const {
[[nodiscard]] const StickersSetsOrder &archivedSetsOrder() const {
return _archivedSetsOrder;
}
StickersSetsOrder &archivedSetsOrderRef() {
[[nodiscard]] StickersSetsOrder &archivedSetsOrderRef() {
return _archivedSetsOrder;
}
const StickersSetsOrder &archivedMaskSetsOrder() const {
[[nodiscard]] const StickersSetsOrder &archivedMaskSetsOrder() const {
return _archivedMaskSetsOrder;
}
StickersSetsOrder &archivedMaskSetsOrderRef() {
[[nodiscard]] StickersSetsOrder &archivedMaskSetsOrderRef() {
return _archivedMaskSetsOrder;
}
const SavedGifs &savedGifs() const {
[[nodiscard]] const SavedGifs &savedGifs() const {
return _savedGifs;
}
SavedGifs &savedGifsRef() {
[[nodiscard]] SavedGifs &savedGifsRef() {
return _savedGifs;
}
void removeFromRecentSet(not_null<DocumentData*> document);
@ -214,7 +214,7 @@ public:
const MTPDmessages_stickerSetInstallResultArchive &d);
void installLocally(uint64 setId);
void undoInstallLocally(uint64 setId);
bool isFaved(not_null<const DocumentData*> document);
[[nodiscard]] bool isFaved(not_null<const DocumentData*> document) const;
void setFaved(
std::shared_ptr<ChatHelpers::Show> show,
not_null<DocumentData*> document,
@ -235,12 +235,12 @@ public:
const MTPmessages_FeaturedStickers &result);
void gifsReceived(const QVector<MTPDocument> &items, uint64 hash);
std::vector<not_null<DocumentData*>> getListByEmoji(
[[nodiscard]] std::vector<not_null<DocumentData*>> getListByEmoji(
std::vector<EmojiPtr> emoji,
uint64 seed,
bool forceAllResults = false);
std::optional<std::vector<not_null<EmojiPtr>>> getEmojiListFromSet(
not_null<DocumentData*> document);
[[nodiscard]] auto getEmojiListFromSet(not_null<DocumentData*> document)
-> std::optional<std::vector<not_null<EmojiPtr>>>;
not_null<StickersSet*> feedSet(const MTPStickerSet &data);
not_null<StickersSet*> feedSet(const MTPStickerSetCovered &data);
@ -254,15 +254,14 @@ public:
const QVector<MTPDocument> &documents);
void newSetReceived(const MTPDmessages_stickerSet &set);
QString getSetTitle(const MTPDstickerSet &s);
[[nodiscard]] QString getSetTitle(const MTPDstickerSet &s);
RecentStickerPack &getRecentPack() const;
[[nodiscard]] RecentStickerPack &getRecentPack() const;
private:
bool updateNeeded(crl::time lastUpdate, crl::time now) const {
[[nodiscard]] bool updateNeeded(crl::time last, crl::time now) const {
constexpr auto kUpdateTimeout = crl::time(3600'000);
return (lastUpdate == 0)
|| (now >= lastUpdate + kUpdateTimeout);
return (last == 0) || (now >= last + kUpdateTimeout);
}
void checkFavedLimit(
StickersSet &set,

View file

@ -4072,7 +4072,7 @@ void HistoryInner::refreshAboutView() {
_history->delegateMixin()->delegate());
}
if (!info->inited) {
session().api().requestFullPeer(_peer);
session().api().requestFullPeer(user);
}
} else if (user->meRequiresPremiumToWrite()
&& !user->session().premium()
@ -4082,8 +4082,15 @@ void HistoryInner::refreshAboutView() {
_history,
_history->delegateMixin()->delegate());
}
} else {
_aboutView = nullptr;
} else if (!historyHeight()) {
if (!_aboutView) {
_aboutView = std::make_unique<HistoryView::AboutView>(
_history,
_history->delegateMixin()->delegate());
}
if (!user->isFullLoaded()) {
session().api().requestFullPeer(user);
}
}
}
}

View file

@ -7,6 +7,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_about_view.h"
#include "api/api_premium.h"
#include "apiwrap.h"
#include "base/random.h"
#include "chat_helpers/stickers_lottie.h"
#include "core/click_handler_types.h"
#include "data/business/data_business_common.h"
@ -70,47 +73,11 @@ private:
};
class ChatIntroBox final : public ServiceBoxContent {
public:
ChatIntroBox(not_null<Element*> parent, Data::ChatIntro data);
~ChatIntroBox();
int width() override;
int top() override;
QSize size() override;
QString title() override;
TextWithEntities subtitle() override;
int buttonSkip() override;
rpl::producer<QString> button() override;
void draw(
Painter &p,
const PaintContext &context,
const QRect &geometry) override;
ClickHandlerPtr createViewLink() override;
bool hideServiceText() override {
return true;
}
void stickerClearLoopPlayed() override;
std::unique_ptr<StickerPlayer> stickerTakePlayer(
not_null<DocumentData*> data,
const Lottie::ColorReplacements *replacements) override;
bool hasHeavyPart() override;
void unloadHeavyPart() override;
private:
const not_null<Element*> _parent;
const Data::ChatIntro _data;
mutable std::optional<Sticker> _sticker;
};
auto GenerateChatIntro(
not_null<Element*> parent,
Element *replacing,
const Data::ChatIntro &data)
const Data::ChatIntro &data,
Fn<void(not_null<DocumentData*>)> helloChosen)
-> Fn<void(Fn<void(std::unique_ptr<MediaInBubble::Part>)>)> {
return [=](Fn<void(std::unique_ptr<MediaInBubble::Part>)> push) {
auto pushText = [&](
@ -137,8 +104,19 @@ auto GenerateChatIntro(
: st::chatIntroMargin);
const auto sticker = [=] {
using Tag = ChatHelpers::StickerLottieSize;
auto sticker = data.sticker;
if (!sticker) {
const auto api = &parent->history()->session().api();
const auto &list = api->premium().helloStickers();
if (!list.empty()) {
sticker = list[base::RandomIndex(list.size())];
if (helloChosen) {
helloChosen(sticker);
}
}
}
return StickerInBubblePart::Data{
.sticker = data.sticker,
.sticker = sticker,
.size = st::chatIntroStickerSize,
.cacheTag = Tag::ChatIntroHelloSticker,
};
@ -220,96 +198,6 @@ bool PremiumRequiredBox::hasHeavyPart() {
void PremiumRequiredBox::unloadHeavyPart() {
}
ChatIntroBox::ChatIntroBox(not_null<Element*> parent, Data::ChatIntro data)
: _parent(parent)
, _data(data) {
if (const auto document = data.sticker) {
if (const auto sticker = document->sticker()) {
const auto skipPremiumEffect = true;
_sticker.emplace(_parent, document, skipPremiumEffect, _parent);
_sticker->initSize(st::chatIntroStickerSize);
_sticker->setCustomCachingTag(
ChatHelpers::StickerLottieSize::ChatIntroHelloSticker);
}
}
}
ChatIntroBox::~ChatIntroBox() = default;
int ChatIntroBox::width() {
return st::chatIntroWidth;
}
int ChatIntroBox::top() {
return st::msgServiceGiftBoxButtonMargins.top();
}
QSize ChatIntroBox::size() {
return { st::msgServicePhotoWidth, st::msgServicePhotoWidth };
}
QString ChatIntroBox::title() {
return _data ? _data.title : tr::lng_chat_intro_default_title(tr::now);
}
int ChatIntroBox::buttonSkip() {
return st::storyMentionButtonSkip;
}
rpl::producer<QString> ChatIntroBox::button() {
return nullptr;
}
TextWithEntities ChatIntroBox::subtitle() {
return {
(_data
? _data.description
: tr::lng_chat_intro_default_message(tr::now))
};
}
ClickHandlerPtr ChatIntroBox::createViewLink() {
return std::make_shared<LambdaClickHandler>([=](ClickContext context) {
const auto my = context.other.value<ClickHandlerContext>();
if (const auto controller = my.sessionWindow.get()) {
Settings::ShowPremium(controller, u"require_premium"_q);
}
});
}
void ChatIntroBox::draw(
Painter &p,
const PaintContext &context,
const QRect &geometry) {
if (_sticker) {
_sticker->draw(p, context, geometry);
}
}
void ChatIntroBox::stickerClearLoopPlayed() {
if (_sticker) {
_sticker->stickerClearLoopPlayed();
}
}
std::unique_ptr<StickerPlayer> ChatIntroBox::stickerTakePlayer(
not_null<DocumentData*> data,
const Lottie::ColorReplacements *replacements) {
return _sticker
? _sticker->stickerTakePlayer(data, replacements)
: nullptr;
}
bool ChatIntroBox::hasHeavyPart() {
return _sticker && _sticker->hasHeavyPart();
}
void ChatIntroBox::unloadHeavyPart() {
if (_sticker) {
_sticker->unloadHeavyPart();
}
}
} // namespace
AboutView::AboutView(
@ -339,21 +227,22 @@ HistoryItem *AboutView::item() const {
}
bool AboutView::refresh() {
const auto bot = _history->peer->asUser();
const auto info = bot ? bot->botInfo.get() : nullptr;
const auto user = _history->peer->asUser();
const auto info = user ? user->botInfo.get() : nullptr;
if (!info) {
if (bot
&& bot->meRequiresPremiumToWrite()
&& !bot->session().premium()
&& _history->isDisplayedEmpty()) {
if (user && _history->isDisplayedEmpty()) {
if (_item) {
return false;
} else if (user->meRequiresPremiumToWrite()
&& !user->session().premium()) {
setItem(makePremiumRequired(), nullptr);
} else {
makeIntro(user);
}
_item = makePremiumRequired();
return true;
}
if (_item) {
_item = {};
setItem({}, nullptr);
return true;
}
_version = 0;
@ -364,10 +253,14 @@ bool AboutView::refresh() {
return false;
}
_version = version;
_item = makeAboutBot(info);
setItem(makeAboutBot(info), nullptr);
return true;
}
void AboutView::makeIntro(not_null<UserData*> user) {
make(user->businessDetails().intro);
}
void AboutView::make(Data::ChatIntro data) {
const auto item = _history->makeMessage({
.id = _history->nextNonHistoryEntryId(),
@ -377,31 +270,58 @@ void AboutView::make(Data::ChatIntro data) {
.from = _history->peer->id,
}, PreparedServiceText{ { } });
if (data.sticker) {
_helloChosen = nullptr;
} else if (_helloChosen) {
data.sticker = _helloChosen;
}
auto owned = AdminLog::OwnedItem(_delegate, item);
const auto helloChosen = [=](not_null<DocumentData*> sticker) {
setHelloChosen(sticker);
};
owned->overrideMedia(std::make_unique<HistoryView::MediaInBubble>(
owned.get(),
GenerateChatIntro(owned.get(), _item.get(), data),
GenerateChatIntro(owned.get(), _item.get(), data, helloChosen),
HistoryView::MediaInBubbleDescriptor{
.maxWidth = st::chatIntroWidth,
.service = true,
.hideServiceText = true,
}));
if (!data.sticker && _helloChosen) {
data.sticker = _helloChosen;
}
setItem(std::move(owned), data.sticker);
}
void AboutView::setItem(AdminLog::OwnedItem item, DocumentData *sticker) {
if (const auto was = _item ? _item->data().get() : nullptr) {
void AboutView::toggleStickerRegistered(bool registered) {
if (const auto item = _item ? _item->data().get() : nullptr) {
if (_sticker) {
was->history()->owner().unregisterDocumentItem(_sticker, was);
const auto owner = &item->history()->owner();
if (registered) {
owner->registerDocumentItem(_sticker, item);
} else {
owner->unregisterDocumentItem(_sticker, item);
}
}
}
if (!registered) {
_sticker = nullptr;
}
}
void AboutView::setHelloChosen(not_null<DocumentData*> sticker) {
_helloChosen = sticker;
toggleStickerRegistered(false);
_sticker = sticker;
toggleStickerRegistered(true);
}
void AboutView::setItem(AdminLog::OwnedItem item, DocumentData *sticker) {
toggleStickerRegistered(false);
_item = std::move(item);
_sticker = sticker;
if (const auto now = _item ? _item->data().get() : nullptr) {
if (_sticker) {
now->history()->owner().registerDocumentItem(_sticker, now);
}
}
toggleStickerRegistered(true);
}
AdminLog::OwnedItem AboutView::makeAboutBot(not_null<BotInfo*> info) {

View file

@ -36,11 +36,15 @@ public:
private:
[[nodiscard]] AdminLog::OwnedItem makeAboutBot(not_null<BotInfo*> info);
[[nodiscard]] AdminLog::OwnedItem makePremiumRequired();
void makeIntro(not_null<UserData*> user);
void setItem(AdminLog::OwnedItem item, DocumentData *sticker);
void setHelloChosen(not_null<DocumentData*> sticker);
void toggleStickerRegistered(bool registered);
const not_null<History*> _history;
const not_null<ElementDelegate*> _delegate;
AdminLog::OwnedItem _item;
DocumentData *_helloChosen = nullptr;
DocumentData *_sticker = nullptr;
int _version = 0;

View file

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "history/view/media/history_view_media_common.h"
#include "history/view/media/history_view_sticker_player.h"
#include "history/view/history_view_about_view.h"
@ -564,10 +565,8 @@ void ChatIntro::setupContent(
const auto content = Ui::CreateChild<Ui::VerticalLayout>(this);
const auto session = &controller->session();
const auto info = &session->data().businessInfo();
const auto current = info->chatIntro();
_intro = controller->session().user()->businessDetails().intro;
_intro = info->chatIntro();
const auto change = [=](Fn<void(Data::ChatIntro &)> modify) {
auto intro = _intro.current();
modify(intro);
@ -584,12 +583,12 @@ void ChatIntro::setupContent(
const auto title = AddPartInput(
content,
tr::lng_chat_intro_enter_title(),
current.title,
_intro.current().title,
PartLimit(session, u"intro_title_length_limit"_q, 32));
const auto description = AddPartInput(
content,
tr::lng_chat_intro_enter_message(),
current.description,
_intro.current().description,
PartLimit(session, u"intro_description_length_limit"_q, 70));
content->add(CreateIntroStickerButton(
content,