mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
"Set Bot Photo" button in managed bots.
This commit is contained in:
@@ -2589,6 +2589,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
"lng_managed_bot_created_text" = "{parent_name} will manage this bot for you.";
|
||||
"lng_managed_bot_edit_photo" = "You can edit your bot's profile picture {link}";
|
||||
"lng_managed_bot_edit_photo_link" = "here {arrow}";
|
||||
"lng_managed_bot_set_photo" = "Set Profile Photo";
|
||||
|
||||
"lng_stake_game_title" = "Emoji Stake";
|
||||
"lng_stake_game_beta" = "Beta";
|
||||
|
||||
@@ -968,6 +968,16 @@ historyEmojiStatusInfoLabel: FlatLabel(historyContactStatusLabel) {
|
||||
}
|
||||
historyContactStatusMinSkip: 16px;
|
||||
|
||||
historySetBotPhotoIcon: icon {{ "menu/photo_set", windowActiveTextFg }};
|
||||
historySetBotPhotoIconSize: 49px;
|
||||
historySetBotPhotoLabel: FlatLabel(defaultFlatLabel) {
|
||||
style: semiboldTextStyle;
|
||||
textFg: windowActiveTextFg;
|
||||
align: align(center);
|
||||
maxHeight: 30px;
|
||||
}
|
||||
historySetBotPhotoLabelMarginRight: 20px;
|
||||
|
||||
historyBusinessBotPhoto: UserpicButton(defaultUserpicButton) {
|
||||
size: size(46px, 46px);
|
||||
photoSize: 46px;
|
||||
|
||||
@@ -121,9 +121,10 @@ struct PeerUpdate {
|
||||
ChannelLocation = (1ULL << 53),
|
||||
Slowmode = (1ULL << 54),
|
||||
GroupCall = (1ULL << 55),
|
||||
ManagedBot = (1ULL << 56),
|
||||
|
||||
// For iteration
|
||||
LastUsedBit = (1ULL << 55),
|
||||
LastUsedBit = (1ULL << 56),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||
|
||||
@@ -565,9 +565,9 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||
if (!hasStarsPerMessage) {
|
||||
result->setStarsPerMessage(0);
|
||||
}
|
||||
result->setBotInfoVersion(data.vbot_info_version().value_or(-1));
|
||||
|
||||
if (!minimal) {
|
||||
result->setBotInfoVersion(data.vbot_info_version().value_or(-1));
|
||||
if (const auto info = result->botInfo.get()) {
|
||||
info->readsAllHistory = data.is_bot_chat_history();
|
||||
if (info->cantJoinGroups != data.is_bot_nochats()) {
|
||||
@@ -581,7 +581,11 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
||||
}
|
||||
info->supportsAttachMenu = data.is_bot_attach_menu();
|
||||
info->supportsBusiness = data.is_bot_business();
|
||||
info->canEditInformation = data.is_bot_can_edit();
|
||||
const auto canEditInformation = data.is_bot_can_edit();
|
||||
if (info->canEditInformation != canEditInformation) {
|
||||
info->canEditInformation = canEditInformation;
|
||||
flags |= UpdateFlag::ManagedBot;
|
||||
}
|
||||
info->activeUsers = data.vbot_active_users().value_or_empty();
|
||||
info->hasMainApp = data.is_bot_has_main_app();
|
||||
info->userCreatesTopics = data.is_bot_forum_can_manage_topics();
|
||||
|
||||
@@ -323,7 +323,11 @@ UserId UserData::botManagerId() const {
|
||||
}
|
||||
|
||||
void UserData::setBotManagerId(UserId managerId) {
|
||||
const auto changed = (_botManagerId != managerId);
|
||||
_botManagerId = managerId;
|
||||
if (changed) {
|
||||
session().changes().peerUpdated(this, UpdateFlag::ManagedBot);
|
||||
}
|
||||
}
|
||||
|
||||
MTPInputUser UserData::inputUser() const {
|
||||
|
||||
@@ -55,6 +55,12 @@ struct BotVerifierSettings {
|
||||
};
|
||||
|
||||
struct BotInfo {
|
||||
enum class SetBotPhotoOpenState : uchar {
|
||||
Unknown,
|
||||
OpenedWithHistory,
|
||||
OpenedEmpty,
|
||||
};
|
||||
|
||||
BotInfo();
|
||||
~BotInfo();
|
||||
|
||||
@@ -90,6 +96,7 @@ struct BotInfo {
|
||||
int version = 0;
|
||||
int descriptionVersion = 0;
|
||||
int activeUsers = 0;
|
||||
SetBotPhotoOpenState setBotPhotoOpenState = SetBotPhotoOpenState::Unknown;
|
||||
bool inited : 1 = false;
|
||||
bool readsAllHistory : 1 = false;
|
||||
bool cantJoinGroups : 1 = false;
|
||||
@@ -99,6 +106,7 @@ struct BotInfo {
|
||||
bool supportsBusiness : 1 = false;
|
||||
bool hasMainApp : 1 = false;
|
||||
bool userCreatesTopics : 1 = false;
|
||||
bool setBotPhotoHidden : 1 = false;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Data::Forum> _forum;
|
||||
|
||||
@@ -849,6 +849,7 @@ HistoryWidget::HistoryWidget(
|
||||
| PeerUpdateFlag::MessagesTTL
|
||||
| PeerUpdateFlag::ChatThemeToken
|
||||
| PeerUpdateFlag::FullInfo
|
||||
| PeerUpdateFlag::ManagedBot
|
||||
| PeerUpdateFlag::StarsPerMessage
|
||||
| PeerUpdateFlag::GiftSettings
|
||||
) | rpl::filter([=](const Data::PeerUpdate &update) {
|
||||
@@ -909,6 +910,10 @@ HistoryWidget::HistoryWidget(
|
||||
if (flags & PeerUpdateFlag::Slowmode) {
|
||||
updateSendButtonType();
|
||||
}
|
||||
if ((flags & PeerUpdateFlag::ManagedBot) && _list) {
|
||||
_list->refreshAboutView();
|
||||
_list->updateBotInfo();
|
||||
}
|
||||
if (flags & (PeerUpdateFlag::IsBlocked
|
||||
| PeerUpdateFlag::Admins
|
||||
| PeerUpdateFlag::Members
|
||||
|
||||
@@ -1189,21 +1189,6 @@ AdminLog::OwnedItem AboutView::makeManagedBotInfo(
|
||||
tr::bold(parentName),
|
||||
tr::rich);
|
||||
|
||||
const auto url = u"internal:edit_peer/"_q
|
||||
+ QString::number(user->id.value);
|
||||
text.append(u"\n\n"_q).append(tr::lng_managed_bot_edit_photo(
|
||||
tr::now,
|
||||
lt_link,
|
||||
Ui::Text::Wrapped(
|
||||
tr::lng_managed_bot_edit_photo_link(
|
||||
tr::now,
|
||||
lt_arrow,
|
||||
Ui::Text::IconEmoji(&st::textMoreIconEmoji),
|
||||
tr::rich),
|
||||
EntityType::CustomUrl,
|
||||
url),
|
||||
tr::rich));
|
||||
|
||||
return makeAboutSimple(text, nullptr, photo);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "chat_helpers/message_field.h" // PaidSendButtonText
|
||||
#include "core/click_handler_types.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "history/history.h"
|
||||
#include "data/business/data_business_chatbots.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/data_emoji_statuses.h"
|
||||
@@ -75,6 +76,19 @@ namespace {
|
||||
return false;
|
||||
}
|
||||
|
||||
void FinalizeSetBotPhotoFirstOpenState(not_null<PeerData*> peer) {
|
||||
using State = BotInfo::SetBotPhotoOpenState;
|
||||
|
||||
const auto user = peer->asUser();
|
||||
const auto info = user ? user->botInfo.get() : nullptr;
|
||||
if (!info || (info->setBotPhotoOpenState != State::Unknown)) {
|
||||
return;
|
||||
}
|
||||
info->setBotPhotoOpenState = peer->owner().history(peer)->lastMessage()
|
||||
? State::OpenedWithHistory
|
||||
: State::OpenedEmpty;
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<TextWithEntities> ResolveIsCustom(
|
||||
not_null<Data::Session*> owner,
|
||||
DocumentId id) {
|
||||
@@ -140,6 +154,53 @@ namespace {
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RippleButton> SetupSetBotPhotoButton(
|
||||
object_ptr<Ui::RippleButton> button) {
|
||||
const auto raw = button.data();
|
||||
|
||||
const auto icon = Ui::CreateChild<Ui::RpWidget>(raw);
|
||||
icon->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
icon->paintRequest(
|
||||
) | rpl::on_next([=] {
|
||||
auto p = QPainter(icon);
|
||||
st::historySetBotPhotoIcon.paintInCenter(p, icon->rect());
|
||||
}, icon->lifetime());
|
||||
|
||||
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
||||
raw,
|
||||
tr::lng_managed_bot_set_photo(tr::now),
|
||||
st::historySetBotPhotoLabel);
|
||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
|
||||
raw->sizeValue(
|
||||
) | rpl::on_next([=](QSize size) {
|
||||
const auto closeWidth = st::historyReplyCancel.width;
|
||||
const auto iconWidth = st::historySetBotPhotoIconSize;
|
||||
const auto margin = st::historySetBotPhotoLabelMarginRight;
|
||||
const auto available = size.width() - closeWidth - margin;
|
||||
const auto labelNatural = label->naturalWidth();
|
||||
const auto labelWidth = std::max(
|
||||
0,
|
||||
std::min(labelNatural, available - iconWidth));
|
||||
const auto totalContent = iconWidth + labelWidth;
|
||||
const auto contentLeft = std::max(0, (available - totalContent) / 2);
|
||||
icon->setGeometry(
|
||||
contentLeft,
|
||||
0,
|
||||
iconWidth,
|
||||
size.height());
|
||||
label->resizeToWidth(labelWidth);
|
||||
label->moveToLeft(
|
||||
contentLeft + iconWidth,
|
||||
(size.height() - label->height()) / 2,
|
||||
size.width());
|
||||
icon->raise();
|
||||
label->raise();
|
||||
}, raw->lifetime());
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class ContactStatus::BgButton final : public Ui::RippleButton {
|
||||
@@ -173,6 +234,7 @@ public:
|
||||
[[nodiscard]] rpl::producer<> closeClicks() const;
|
||||
[[nodiscard]] rpl::producer<> requestInfoClicks() const;
|
||||
[[nodiscard]] rpl::producer<> emojiStatusClicks() const;
|
||||
[[nodiscard]] rpl::producer<> setBotPhotoClicks() const;
|
||||
|
||||
private:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
@@ -192,6 +254,7 @@ private:
|
||||
object_ptr<Ui::FlatLabel> _requestChatInfo;
|
||||
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _emojiStatusInfo;
|
||||
object_ptr<Ui::PlainShadow> _emojiStatusShadow;
|
||||
object_ptr<Ui::RippleButton> _setBotPhoto;
|
||||
bool _emojiStatusRepaintScheduled = false;
|
||||
bool _narrow = false;
|
||||
rpl::event_stream<> _emojiStatusClicks;
|
||||
@@ -260,7 +323,10 @@ ContactStatus::Bar::Bar(
|
||||
st::topBarArrowPadding.top(),
|
||||
st::historyContactStatusMinSkip,
|
||||
st::topBarArrowPadding.top()))
|
||||
, _emojiStatusShadow(this) {
|
||||
, _emojiStatusShadow(this)
|
||||
, _setBotPhoto(
|
||||
SetupSetBotPhotoButton(
|
||||
object_ptr<BgButton>(this, st::historyContactStatusButton))) {
|
||||
_close->setAccessibleName(tr::lng_cancel(tr::now));
|
||||
_unarchiveIcon->setAccessibleName(tr::lng_new_contact_unarchive(tr::now));
|
||||
_reportIcon->setAccessibleName(tr::lng_report_spam(tr::now));
|
||||
@@ -286,13 +352,16 @@ void ContactStatus::Bar::showState(
|
||||
_block->setVisible(type == Type::AddOrBlock
|
||||
|| type == Type::UnarchiveOrBlock);
|
||||
_share->setVisible(type == Type::SharePhoneNumber);
|
||||
_close->setVisible(!_narrow && type != Type::RequestChatInfo);
|
||||
_close->setVisible(
|
||||
(!_narrow && type != Type::RequestChatInfo)
|
||||
|| type == Type::SetBotPhoto);
|
||||
const auto report = (type == Type::ReportSpam)
|
||||
|| (type == Type::UnarchiveOrReport);
|
||||
_report->setVisible(!_narrow && report);
|
||||
_reportIcon->setVisible(_narrow && report);
|
||||
_requestChatInfo->setVisible(type == Type::RequestChatInfo);
|
||||
_requestChatBg->setVisible(type == Type::RequestChatInfo);
|
||||
_setBotPhoto->setVisible(type == Type::SetBotPhoto);
|
||||
const auto has = !status.empty();
|
||||
_emojiStatusShadow->setVisible(
|
||||
has && (type == Type::AddOrBlock || type == Type::UnarchiveOrBlock));
|
||||
@@ -373,12 +442,18 @@ rpl::producer<> ContactStatus::Bar::emojiStatusClicks() const {
|
||||
return _emojiStatusClicks.events();
|
||||
}
|
||||
|
||||
rpl::producer<> ContactStatus::Bar::setBotPhotoClicks() const {
|
||||
return _setBotPhoto->clicks() | rpl::to_empty;
|
||||
}
|
||||
|
||||
int ContactStatus::Bar::resizeGetHeight(int newWidth) {
|
||||
_close->moveToRight(0, 0, newWidth);
|
||||
const auto narrow = (newWidth < _close->width() * 2);
|
||||
if (_narrow != narrow) {
|
||||
_narrow = narrow;
|
||||
_close->setVisible(_requestChatInfo->isHidden() && !_narrow);
|
||||
_close->setVisible(
|
||||
(_requestChatInfo->isHidden() && !_narrow)
|
||||
|| !_setBotPhoto->isHidden());
|
||||
const auto report = !_report->isHidden() || !_reportIcon->isHidden();
|
||||
_report->setVisible(!_narrow && report);
|
||||
_reportIcon->setVisible(_narrow && report);
|
||||
@@ -388,6 +463,13 @@ int ContactStatus::Bar::resizeGetHeight(int newWidth) {
|
||||
_unarchiveIcon->setVisible(_narrow && unarchive);
|
||||
}
|
||||
|
||||
if (!_setBotPhoto->isHidden()) {
|
||||
const auto closeHeight = _close->height();
|
||||
_setBotPhoto->setGeometry(0, 0, newWidth, closeHeight);
|
||||
_close->raise();
|
||||
return closeHeight;
|
||||
}
|
||||
|
||||
if (!_unarchiveIcon->isHidden()) {
|
||||
const auto half = newWidth / 2;
|
||||
_unarchiveIcon->setGeometry(0, 0, half, _close->height());
|
||||
@@ -568,6 +650,7 @@ ContactStatus::ContactStatus(
|
||||
: _controller(window)
|
||||
, _inner(Ui::CreateChild<Bar>(parent.get(), peer->shortName()))
|
||||
, _bar(parent, object_ptr<Bar>::fromRaw(_inner)) {
|
||||
FinalizeSetBotPhotoFirstOpenState(peer);
|
||||
setupState(peer, showInForum);
|
||||
setupHandlers(peer);
|
||||
}
|
||||
@@ -585,12 +668,22 @@ auto ContactStatus::PeerState(not_null<PeerData*> peer)
|
||||
return flags.diff
|
||||
& (Flag::Contact | Flag::MutualContact | Flag::Blocked);
|
||||
});
|
||||
auto managedBotChanges = user->session().changes().peerFlagsValue(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::ManagedBot);
|
||||
auto photoChanges = user->session().changes().peerFlagsValue(
|
||||
user,
|
||||
Data::PeerUpdate::Flag::Photo);
|
||||
return rpl::combine(
|
||||
std::move(changes),
|
||||
user->barSettingsValue()
|
||||
user->barSettingsValue(),
|
||||
std::move(photoChanges),
|
||||
std::move(managedBotChanges)
|
||||
) | rpl::map([=](
|
||||
FlagsChange flags,
|
||||
SettingsChange settings) -> State {
|
||||
SettingsChange settings,
|
||||
const auto &,
|
||||
const auto &) -> State {
|
||||
if (flags.value & Flag::Blocked) {
|
||||
return { Type::None };
|
||||
} else if (user->isContact()) {
|
||||
@@ -613,6 +706,22 @@ auto ContactStatus::PeerState(not_null<PeerData*> peer)
|
||||
return { Type::AddOrBlock };
|
||||
} else if (settings.value & PeerBarSetting::AddContact) {
|
||||
return { Type::Add };
|
||||
} else if (user->botManagerId()) {
|
||||
if (const auto info = user->botInfo.get()) {
|
||||
if (info->canEditInformation) {
|
||||
const auto hasUserpic = user->hasUserpic();
|
||||
if (hasUserpic) {
|
||||
info->setBotPhotoHidden = true;
|
||||
}
|
||||
using State = BotInfo::SetBotPhotoOpenState;
|
||||
if (info->setBotPhotoOpenState == State::OpenedEmpty
|
||||
&& !info->setBotPhotoHidden
|
||||
&& !hasUserpic) {
|
||||
return { Type::SetBotPhoto };
|
||||
}
|
||||
}
|
||||
}
|
||||
return { Type::None };
|
||||
} else {
|
||||
return { Type::None };
|
||||
}
|
||||
@@ -665,6 +774,7 @@ void ContactStatus::setupHandlers(not_null<PeerData*> peer) {
|
||||
setupAddHandler(user);
|
||||
setupBlockHandler(user);
|
||||
setupShareHandler(user);
|
||||
setupSetBotPhotoHandler(user);
|
||||
}
|
||||
setupUnarchiveHandler(peer);
|
||||
setupReportHandler(peer);
|
||||
@@ -785,6 +895,16 @@ void ContactStatus::setupCloseHandler(not_null<PeerData*> peer) {
|
||||
) | rpl::filter([=] {
|
||||
return !(*request);
|
||||
}) | rpl::on_next([=] {
|
||||
if (_state.type == State::Type::SetBotPhoto) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (const auto info = user->botInfo.get()) {
|
||||
info->setBotPhotoHidden = true;
|
||||
}
|
||||
}
|
||||
_state = {};
|
||||
_bar.toggleContent(false);
|
||||
return;
|
||||
}
|
||||
peer->setBarSettings(0);
|
||||
*request = peer->session().api().request(
|
||||
MTPmessages_HidePeerSettingsBar(peer->input())
|
||||
@@ -836,6 +956,13 @@ void ContactStatus::setupEmojiStatusHandler(not_null<PeerData*> peer) {
|
||||
}, _bar.lifetime());
|
||||
}
|
||||
|
||||
void ContactStatus::setupSetBotPhotoHandler(not_null<UserData*> user) {
|
||||
_inner->setBotPhotoClicks(
|
||||
) | rpl::on_next([=] {
|
||||
_controller->showEditPeerBox(user);
|
||||
}, _bar.lifetime());
|
||||
}
|
||||
|
||||
void ContactStatus::show() {
|
||||
if (!_shown) {
|
||||
_shown = true;
|
||||
|
||||
@@ -93,6 +93,7 @@ private:
|
||||
UnarchiveOrReport,
|
||||
SharePhoneNumber,
|
||||
RequestChatInfo,
|
||||
SetBotPhoto,
|
||||
};
|
||||
Type type = Type::None;
|
||||
int starsPerMessage = 0;
|
||||
@@ -111,6 +112,7 @@ private:
|
||||
void setupCloseHandler(not_null<PeerData*> peer);
|
||||
void setupRequestInfoHandler(not_null<PeerData*> peer);
|
||||
void setupEmojiStatusHandler(not_null<PeerData*> peer);
|
||||
void setupSetBotPhotoHandler(not_null<UserData*> user);
|
||||
|
||||
static rpl::producer<State> PeerState(not_null<PeerData*> peer);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user