diff --git a/Telegram/Resources/animations/hello_status.tgs b/Telegram/Resources/animations/hello_status.tgs
new file mode 100644
index 000000000..b48182c2c
Binary files /dev/null and b/Telegram/Resources/animations/hello_status.tgs differ
diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 23b7ae0c9..9c0aa15d6 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -1461,6 +1461,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_open_app" = "Open App";
"lng_profile_open_app_about" = "By launching this mini app, you agree to the {terms}.";
"lng_profile_open_app_terms" = "Terms of Service for Mini Apps";
+"lng_profile_bot_permissions_title" = "Allow access to";
+"lng_profile_bot_emoji_status_access" = "Emoji Status";
"lng_info_add_as_contact" = "Add to contacts";
"lng_profile_shared_media" = "Shared media";
"lng_profile_suggest_photo" = "Suggest Profile Photo";
@@ -3421,6 +3423,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_bot_emoji_status_confirm" = "Confirm";
"lng_bot_emoji_status_title" = "Set Emoji Status";
"lng_bot_emoji_status_text" = "Do you want to set this emoji status suggested by {bot}?";
+"lng_bot_emoji_status_access_text" = "{bot} requests access to set your **emoji status**. You will be able to revoke this access in the profile page of {name}.";
+"lng_bot_emoji_status_access_allow" = "Allow";
"lng_bot_status_users#one" = "{count} monthly user";
"lng_bot_status_users#other" = "{count} monthly users";
diff --git a/Telegram/Resources/qrc/telegram/animations.qrc b/Telegram/Resources/qrc/telegram/animations.qrc
index ac6ff1dbf..f60061f99 100644
--- a/Telegram/Resources/qrc/telegram/animations.qrc
+++ b/Telegram/Resources/qrc/telegram/animations.qrc
@@ -28,6 +28,7 @@
../../animations/collectible_phone.tgs
../../animations/search.tgs
../../animations/noresults.tgs
+ ../../animations/hello_status.tgs
../../animations/dice/dice_idle.tgs
../../animations/dice/dart_idle.tgs
diff --git a/Telegram/SourceFiles/data/data_document.cpp b/Telegram/SourceFiles/data/data_document.cpp
index af5f95077..c14d29bfc 100644
--- a/Telegram/SourceFiles/data/data_document.cpp
+++ b/Telegram/SourceFiles/data/data_document.cpp
@@ -745,6 +745,14 @@ bool DocumentData::emojiUsesTextColor() const {
return (_flags & Flag::UseTextColor);
}
+void DocumentData::overrideEmojiUsesTextColor(bool value) {
+ if (value) {
+ _flags |= Flag::UseTextColor;
+ } else {
+ _flags &= ~Flag::UseTextColor;
+ }
+}
+
bool DocumentData::hasThumbnail() const {
return _thumbnail.location.valid()
&& !thumbnailFailed()
diff --git a/Telegram/SourceFiles/data/data_document.h b/Telegram/SourceFiles/data/data_document.h
index df1f9eab3..6aa21caa9 100644
--- a/Telegram/SourceFiles/data/data_document.h
+++ b/Telegram/SourceFiles/data/data_document.h
@@ -206,6 +206,7 @@ public:
[[nodiscard]] bool isPremiumSticker() const;
[[nodiscard]] bool isPremiumEmoji() const;
[[nodiscard]] bool emojiUsesTextColor() const;
+ void overrideEmojiUsesTextColor(bool value);
[[nodiscard]] bool hasThumbnail() const;
[[nodiscard]] bool thumbnailLoading() const;
diff --git a/Telegram/SourceFiles/data/data_user.cpp b/Telegram/SourceFiles/data/data_user.cpp
index 2456567d3..7433dbd9a 100644
--- a/Telegram/SourceFiles/data/data_user.cpp
+++ b/Telegram/SourceFiles/data/data_user.cpp
@@ -580,6 +580,9 @@ void ApplyUserUpdate(not_null user, const MTPDuserFull &update) {
} else {
user->setBotInfoVersion(-1);
}
+ if (const auto info = user->botInfo.get()) {
+ info->canManageEmojiStatus = update.is_bot_can_manage_emoji_status();
+ }
if (const auto pinned = update.vpinned_msg_id()) {
SetTopPinnedMessageId(user, pinned->v);
}
diff --git a/Telegram/SourceFiles/history/history_inner_widget.cpp b/Telegram/SourceFiles/history/history_inner_widget.cpp
index 41e33a6b0..2753b0dc0 100644
--- a/Telegram/SourceFiles/history/history_inner_widget.cpp
+++ b/Telegram/SourceFiles/history/history_inner_widget.cpp
@@ -2435,6 +2435,14 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (const auto sticker = emojiStickers->stickerForEmoji(
isolated)) {
addDocumentActions(sticker.document, item);
+ } else if (v::is(isolated.items.front())
+ && v::is_null(isolated.items[1])) {
+ const auto id = v::get(isolated.items.front());
+ const auto docId = id.toULongLong();
+ const auto document = session->data().document(docId);
+ if (document->sticker()) {
+ addDocumentActions(document, item);
+ }
}
}
}
diff --git a/Telegram/SourceFiles/info/info.style b/Telegram/SourceFiles/info/info.style
index ae7037a2c..05796c024 100644
--- a/Telegram/SourceFiles/info/info.style
+++ b/Telegram/SourceFiles/info/info.style
@@ -470,6 +470,7 @@ infoIconMediaSaved: icon {{ "info/info_media_saved", infoIconFg }};
infoIconMediaStoriesArchive: icon {{ "info/info_stories_archive", infoIconFg }};
infoIconMediaStoriesRecent: icon {{ "info/info_stories_recent", infoIconFg }};
infoIconMediaGifts: icon {{ "menu/gift_premium", infoIconFg, point(4px, 4px) }};
+infoIconEmojiStatusAccess: icon {{ "menu/read_reactions", infoIconFg, point(4px, 4px) }};
infoIconShare: icon {{ "info/info_share", infoIconFg }};
infoIconEdit: icon {{ "info/info_edit", infoIconFg }};
diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp
index 40611897a..7ade4a32e 100644
--- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp
+++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp
@@ -958,6 +958,7 @@ private:
object_ptr setupInfo();
object_ptr setupMuteToggle();
void setupMainApp();
+ void setupBotPermissions();
void setupMainButtons();
Ui::MultiSlideTracker fillTopicButtons();
Ui::MultiSlideTracker fillUserButtons(
@@ -1865,6 +1866,37 @@ void DetailsFiller::setupMainApp() {
Ui::AddSkip(_wrap);
}
+void DetailsFiller::setupBotPermissions() {
+ AddSkip(_wrap);
+ AddSubsectionTitle(_wrap, tr::lng_profile_bot_permissions_title());
+ const auto emoji = _wrap->add(
+ object_ptr(
+ _wrap,
+ tr::lng_profile_bot_emoji_status_access(),
+ st::infoSharedMediaButton));
+ object_ptr(
+ emoji,
+ st::infoIconEmojiStatusAccess,
+ st::infoSharedMediaButtonIconPosition);
+
+ const auto user = _peer->asUser();
+ emoji->toggleOn(
+ rpl::single(bool(user->botInfo->canManageEmojiStatus))
+ )->toggledValue() | rpl::filter([=](bool allowed) {
+ return allowed != user->botInfo->canManageEmojiStatus;
+ }) | rpl::start_with_next([=](bool allowed) {
+ user->botInfo->canManageEmojiStatus = allowed;
+ const auto session = &user->session();
+ session->api().request(MTPbots_ToggleUserEmojiStatusPermission(
+ user->inputUser,
+ MTP_bool(allowed)
+ )).send();
+ }, emoji->lifetime());
+ AddSkip(_wrap);
+ AddDivider(_wrap);
+ AddSkip(_wrap);
+}
+
void DetailsFiller::setupMainButtons() {
auto wrapButtons = [=](auto &&callback) {
auto topSkip = _wrap->add(CreateSlideSkipWidget(_wrap));
@@ -2059,6 +2091,9 @@ object_ptr DetailsFiller::fill() {
if (info->hasMainApp) {
setupMainApp();
}
+ if (info->canManageEmojiStatus) {
+ setupBotPermissions();
+ }
}
}
if (!_peer->isSelf()) {
diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp
index f7ff549c2..e1858aa95 100644
--- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp
+++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.cpp
@@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer_rpl.h"
#include "boxes/peer_list_controllers.h"
#include "boxes/share_box.h"
+#include "chat_helpers/stickers_lottie.h"
#include "chat_helpers/tabbed_panel.h"
#include "core/application.h"
#include "core/click_handler_types.h"
@@ -447,11 +448,21 @@ std::unique_ptr MakeEmojiSetStatusPreview(
raw,
rpl::single(peer->name()),
st::botEmojiStatusName);
- auto emojiText = TextWithEntities();
+ const auto makeContext = [=](Fn update) {
+ return Core::MarkedTextContext{
+ .session = &peer->session(),
+ .customEmojiRepaint = update,
+ };
+ };
const auto emoji = raw->lifetime().make_state(
raw,
- rpl::single(emojiText),
- st::botEmojiStatusName);
+ rpl::single(
+ Ui::Text::SingleCustomEmoji(
+ Data::SerializeCustomEmojiId(document->id),
+ document->sticker() ? document->sticker()->alt : QString())),
+ st::botEmojiStatusEmoji,
+ st::defaultPopupMenu,
+ makeContext);
const auto userpic = raw->lifetime().make_state(
raw,
peer,
@@ -496,6 +507,59 @@ std::unique_ptr MakeEmojiSetStatusPreview(
return result;
}
+void ConfirmEmojiStatusAccessBox(
+ not_null box,
+ not_null bot,
+ Fn done) {
+ box->setNoContentMargin(true);
+
+ const auto set = box->lifetime().make_state();
+
+ box->addTopButton(st::boxTitleClose, [=] {
+ box->closeBox();
+ });
+
+ AddSkip(box->verticalLayout(), 4 * st::defaultVerticalListSkip);
+
+ const auto statusIcon = ChatHelpers::GenerateLocalTgsSticker(
+ &bot->session(),
+ u"hello_status"_q);
+ statusIcon->overrideEmojiUsesTextColor(true);
+
+ auto ownedSet = MakeEmojiSetStatusPreview(
+ box,
+ bot->session().user(),
+ statusIcon);
+ box->addRow(
+ object_ptr::fromRaw(ownedSet.release()));
+
+ AddSkip(box->verticalLayout(), 2 * st::defaultVerticalListSkip);
+
+ auto name = Ui::Text::Bold(bot->name());
+ box->addRow(object_ptr(
+ box,
+ tr::lng_bot_emoji_status_access_text(
+ lt_bot,
+ rpl::single(name),
+ lt_name,
+ rpl::single(name),
+ Ui::Text::RichLangValue),
+ st::botEmojiStatusText));
+
+ box->addButton(tr::lng_bot_emoji_status_access_allow(), [=] {
+ *set = true;
+ box->closeBox();
+ done(true);
+ });
+ box->addButton(tr::lng_cancel(), [=] {
+ const auto was = *set;
+ box->closeBox();
+ if (!was) {
+ done(false);
+ }
+ });
+}
+
void ConfirmEmojiStatusBox(
not_null box,
not_null bot,
@@ -511,6 +575,10 @@ void ConfirmEmojiStatusBox(
const auto set = box->lifetime().make_state();
+ box->addTopButton(st::boxTitleClose, [=] {
+ box->closeBox();
+ });
+
box->addRow(object_ptr(
box,
tr::lng_bot_emoji_status_title(),
@@ -525,7 +593,7 @@ void ConfirmEmojiStatusBox(
Ui::Text::RichLangValue),
st::botEmojiStatusText));
- AddSkip(box->verticalLayout());
+ AddSkip(box->verticalLayout(), 2 * st::defaultVerticalListSkip);
auto ownedSet = MakeEmojiSetStatusPreview(
box,
@@ -1600,6 +1668,33 @@ void WebViewInstance::botAllowWriteAccess(Fn callback) {
}).send();
}
+void WebViewInstance::botRequestEmojiStatusAccess(
+ Fn callback) {
+ if (_bot->botInfo->canManageEmojiStatus) {
+ callback(true);
+ } else if (const auto panel = _panel.get()) {
+ const auto bot = _bot;
+ panel->showBox(Box(ConfirmEmojiStatusAccessBox, bot, [=](bool ok) {
+ if (!ok) {
+ callback(false);
+ return;
+ }
+ const auto session = &bot->session();
+ bot->botInfo->canManageEmojiStatus = true;
+ session->api().request(MTPbots_ToggleUserEmojiStatusPermission(
+ bot->inputUser,
+ MTP_bool(true)
+ )).done([=] {
+ callback(true);
+ }).fail([=] {
+ callback(false);
+ }).send();
+ }));
+ } else {
+ callback(false);
+ }
+}
+
void WebViewInstance::botSharePhone(Fn callback) {
const auto history = _bot->owner().history(_bot);
if (_bot->isBlocked()) {
diff --git a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h
index b3ce5cbf5..0d7ae73d4 100644
--- a/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h
+++ b/Telegram/SourceFiles/inline_bots/bot_attach_web_view.h
@@ -260,6 +260,8 @@ private:
QString query) override;
void botCheckWriteAccess(Fn callback) override;
void botAllowWriteAccess(Fn callback) override;
+ void botRequestEmojiStatusAccess(
+ Fn callback) override;
void botSharePhone(Fn callback) override;
void botInvokeCustomMethod(
Ui::BotWebView::CustomMethodRequest request) override;
diff --git a/Telegram/SourceFiles/settings/settings_premium.cpp b/Telegram/SourceFiles/settings/settings_premium.cpp
index 172420fd8..b14e9aee1 100644
--- a/Telegram/SourceFiles/settings/settings_premium.cpp
+++ b/Telegram/SourceFiles/settings/settings_premium.cpp
@@ -774,7 +774,7 @@ void TopBarUser::updateTitle(
{ EntityType::CustomEmoji, 0, 1, entityEmojiData },
Ui::Text::Link(text, linkIndex).entities.front(),
};
- auto title = (setId == coloredId)
+ auto title = (setId != coloredId)
? tr::lng_premium_emoji_status_title_colored(
tr::now,
lt_user,
diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.cpp
index 62e9191e1..da2a8a5b8 100644
--- a/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.cpp
+++ b/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.cpp
@@ -826,6 +826,8 @@ bool Panel::createWebview(const Webview::ThemeParams ¶ms) {
processBottomBarColor(arguments);
} else if (command == "web_app_set_emoji_status") {
processEmojiStatusRequest(arguments);
+ } else if (command == "web_app_request_emoji_status_access") {
+ processEmojiStatusAccessRequest();
} else if (command == "share_score") {
_delegate->botHandleMenuButton(MenuButton::ShareGame);
}
@@ -1000,6 +1002,15 @@ void Panel::processEmojiStatusRequest(const QJsonObject &args) {
});
}
+void Panel::processEmojiStatusAccessRequest() {
+ auto callback = crl::guard(this, [=](bool allowed) {
+ postEvent("emoji_status_access_requested", allowed
+ ? "{ status: \"allowed\" }"
+ : "{ status: \"cancelled\" }");
+ });
+ _delegate->botRequestEmojiStatusAccess(std::move(callback));
+}
+
void Panel::openTgLink(const QJsonObject &args) {
if (args.isEmpty()) {
LOG(("BotWebView Error: Bad arguments in 'web_app_open_tg_link'."));
diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.h b/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.h
index 7ea2be451..97da49a60 100644
--- a/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.h
+++ b/Telegram/SourceFiles/ui/chat/attach/attach_bot_webview.h
@@ -71,6 +71,8 @@ public:
QString query) = 0;
virtual void botCheckWriteAccess(Fn callback) = 0;
virtual void botAllowWriteAccess(Fn callback) = 0;
+ virtual void botRequestEmojiStatusAccess(
+ Fn callback) = 0;
virtual void botSharePhone(Fn callback) = 0;
virtual void botInvokeCustomMethod(CustomMethodRequest request) = 0;
virtual void botSetEmojiStatus(SetEmojiStatusRequest request) = 0;
diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style
index eb47373c5..d68c1c933 100644
--- a/Telegram/SourceFiles/ui/chat/chat.style
+++ b/Telegram/SourceFiles/ui/chat/chat.style
@@ -1178,3 +1178,6 @@ botEmojiStatusUserpic: UserpicButton(defaultUserpicButton) {
}
botEmojiStatusName: FlatLabel(defaultFlatLabel) {
}
+botEmojiStatusEmoji: FlatLabel(botEmojiStatusName) {
+ textFg: profileVerifiedCheckBg;
+}