mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 05:07:10 +02:00
Add pays-me status bar in chat.
This commit is contained in:
parent
8ea7bd4913
commit
9032489786
8 changed files with 284 additions and 20 deletions
|
@ -918,6 +918,10 @@ historyBusinessBotSettings: IconButton(defaultIconButton) {
|
|||
height: 58px;
|
||||
width: 48px;
|
||||
}
|
||||
paysStatusLabel: FlatLabel(historyBusinessBotStatus) {
|
||||
align: align(top);
|
||||
minWidth: 240px;
|
||||
}
|
||||
|
||||
historyReplyCancelIcon: icon {{ "box_button_close", historyReplyCancelFg }};
|
||||
historyReplyCancelIconOver: icon {{ "box_button_close", historyReplyCancelFgOver }};
|
||||
|
|
|
@ -95,27 +95,28 @@ struct PeerUpdate {
|
|||
Birthday = (1ULL << 33),
|
||||
PersonalChannel = (1ULL << 34),
|
||||
StarRefProgram = (1ULL << 35),
|
||||
PaysPerMessage = (1ULL << 36),
|
||||
|
||||
// For chats and channels
|
||||
InviteLinks = (1ULL << 36),
|
||||
Members = (1ULL << 37),
|
||||
Admins = (1ULL << 38),
|
||||
BannedUsers = (1ULL << 39),
|
||||
Rights = (1ULL << 40),
|
||||
PendingRequests = (1ULL << 41),
|
||||
Reactions = (1ULL << 42),
|
||||
InviteLinks = (1ULL << 37),
|
||||
Members = (1ULL << 38),
|
||||
Admins = (1ULL << 39),
|
||||
BannedUsers = (1ULL << 40),
|
||||
Rights = (1ULL << 41),
|
||||
PendingRequests = (1ULL << 42),
|
||||
Reactions = (1ULL << 43),
|
||||
|
||||
// For channels
|
||||
ChannelAmIn = (1ULL << 43),
|
||||
StickersSet = (1ULL << 44),
|
||||
EmojiSet = (1ULL << 45),
|
||||
ChannelLinkedChat = (1ULL << 46),
|
||||
ChannelLocation = (1ULL << 47),
|
||||
Slowmode = (1ULL << 48),
|
||||
GroupCall = (1ULL << 49),
|
||||
ChannelAmIn = (1ULL << 44),
|
||||
StickersSet = (1ULL << 45),
|
||||
EmojiSet = (1ULL << 46),
|
||||
ChannelLinkedChat = (1ULL << 47),
|
||||
ChannelLocation = (1ULL << 48),
|
||||
Slowmode = (1ULL << 49),
|
||||
GroupCall = (1ULL << 50),
|
||||
|
||||
// For iteration
|
||||
LastUsedBit = (1ULL << 49),
|
||||
LastUsedBit = (1ULL << 50),
|
||||
};
|
||||
using Flags = base::flags<Flag>;
|
||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||
|
|
|
@ -734,7 +734,7 @@ void PeerData::checkFolder(FolderId folderId) {
|
|||
|
||||
void PeerData::clearBusinessBot() {
|
||||
if (const auto details = _barDetails.get()) {
|
||||
if (details->requestChatDate) {
|
||||
if (details->requestChatDate || details->paysPerMessage) {
|
||||
details->businessBot = nullptr;
|
||||
details->businessBotManageUrl = QString();
|
||||
} else {
|
||||
|
@ -777,7 +777,10 @@ void PeerData::saveTranslationDisabled(bool disabled) {
|
|||
|
||||
void PeerData::setBarSettings(const MTPPeerSettings &data) {
|
||||
data.match([&](const MTPDpeerSettings &data) {
|
||||
if (!data.vbusiness_bot_id() && !data.vrequest_chat_title()) {
|
||||
const auto wasPaysPerMessage = paysPerMessage();
|
||||
if (!data.vbusiness_bot_id()
|
||||
&& !data.vrequest_chat_title()
|
||||
&& !data.vcharge_paid_message_stars()) {
|
||||
_barDetails = nullptr;
|
||||
} else if (!_barDetails) {
|
||||
_barDetails = std::make_unique<PeerBarDetails>();
|
||||
|
@ -792,6 +795,8 @@ void PeerData::setBarSettings(const MTPPeerSettings &data) {
|
|||
: nullptr;
|
||||
_barDetails->businessBotManageUrl
|
||||
= qs(data.vbusiness_bot_manage_url().value_or_empty());
|
||||
_barDetails->paysPerMessage
|
||||
= data.vcharge_paid_message_stars().value_or_empty();
|
||||
}
|
||||
using Flag = PeerBarSetting;
|
||||
setBarSettings((data.is_add_contact() ? Flag::AddContact : Flag())
|
||||
|
@ -815,8 +820,33 @@ void PeerData::setBarSettings(const MTPPeerSettings &data) {
|
|||
| (data.is_business_bot_can_reply()
|
||||
? Flag::BusinessBotCanReply
|
||||
: Flag()));
|
||||
if (wasPaysPerMessage != paysPerMessage()) {
|
||||
session().changes().peerUpdated(
|
||||
this,
|
||||
UpdateFlag::PaysPerMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int PeerData::paysPerMessage() const {
|
||||
return _barDetails ? _barDetails->paysPerMessage : 0;
|
||||
}
|
||||
|
||||
void PeerData::clearPaysPerMessage() {
|
||||
if (const auto details = _barDetails.get()) {
|
||||
if (details->paysPerMessage) {
|
||||
if (details->businessBot || details->requestChatDate) {
|
||||
details->paysPerMessage = 0;
|
||||
} else {
|
||||
_barDetails = nullptr;
|
||||
}
|
||||
session().changes().peerUpdated(
|
||||
this,
|
||||
UpdateFlag::PaysPerMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString PeerData::requestChatTitle() const {
|
||||
return _barDetails ? _barDetails->requestChatTitle : QString();
|
||||
}
|
||||
|
|
|
@ -177,6 +177,7 @@ struct PeerBarDetails {
|
|||
TimeId requestChatDate;
|
||||
UserData *businessBot = nullptr;
|
||||
QString businessBotManageUrl;
|
||||
int paysPerMessage = 0;
|
||||
};
|
||||
|
||||
class PeerData {
|
||||
|
@ -412,6 +413,8 @@ public:
|
|||
? _barSettings.changes()
|
||||
: (_barSettings.value() | rpl::type_erased());
|
||||
}
|
||||
[[nodiscard]] int paysPerMessage() const;
|
||||
void clearPaysPerMessage();
|
||||
[[nodiscard]] QString requestChatTitle() const;
|
||||
[[nodiscard]] TimeId requestChatDate() const;
|
||||
[[nodiscard]] UserData *businessBot() const;
|
||||
|
|
|
@ -1693,6 +1693,9 @@ void HistoryWidget::orderWidgets() {
|
|||
if (_contactStatus) {
|
||||
_contactStatus->bar().raise();
|
||||
}
|
||||
if (_paysStatus) {
|
||||
_paysStatus->bar().raise();
|
||||
}
|
||||
if (_translateBar) {
|
||||
_translateBar->raise();
|
||||
}
|
||||
|
@ -2416,6 +2419,7 @@ void HistoryWidget::showHistory(
|
|||
_showAtMsgId = showAtMsgId;
|
||||
_showAtMsgParams = params;
|
||||
_historyInited = false;
|
||||
_paysStatus = nullptr;
|
||||
_contactStatus = nullptr;
|
||||
_businessBotStatus = nullptr;
|
||||
|
||||
|
@ -2436,6 +2440,14 @@ void HistoryWidget::showHistory(
|
|||
|
||||
refreshGiftToChannelShown();
|
||||
if (const auto user = _peer->asUser()) {
|
||||
_paysStatus = std::make_unique<PaysStatus>(
|
||||
controller(),
|
||||
this,
|
||||
user);
|
||||
_paysStatus->bar().heightValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
updateControlsGeometry();
|
||||
}, _paysStatus->bar().lifetime());
|
||||
_businessBotStatus = std::make_unique<BusinessBotStatus>(
|
||||
controller(),
|
||||
this,
|
||||
|
@ -3077,6 +3089,9 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
if (_requestsBar) {
|
||||
_requestsBar->show();
|
||||
}
|
||||
if (_paysStatus) {
|
||||
_paysStatus->show();
|
||||
}
|
||||
if (_contactStatus) {
|
||||
_contactStatus->show();
|
||||
}
|
||||
|
@ -4305,6 +4320,9 @@ void HistoryWidget::hideChildWidgets() {
|
|||
if (_chooseTheme) {
|
||||
_chooseTheme->hide();
|
||||
}
|
||||
if (_paysStatus) {
|
||||
_paysStatus->hide();
|
||||
}
|
||||
if (_contactStatus) {
|
||||
_contactStatus->hide();
|
||||
}
|
||||
|
@ -6266,8 +6284,13 @@ void HistoryWidget::updateControlsGeometry() {
|
|||
_translateBar->move(0, translateTop);
|
||||
_translateBar->resizeToWidth(width());
|
||||
}
|
||||
const auto contactStatusTop = translateTop
|
||||
const auto paysStatusTop = translateTop
|
||||
+ (_translateBar ? _translateBar->height() : 0);
|
||||
if (_paysStatus) {
|
||||
_paysStatus->bar().move(0, paysStatusTop);
|
||||
}
|
||||
const auto contactStatusTop = paysStatusTop
|
||||
+ (_paysStatus ? _paysStatus->bar().height() : 0);
|
||||
if (_contactStatus) {
|
||||
_contactStatus->bar().move(0, contactStatusTop);
|
||||
}
|
||||
|
@ -6518,6 +6541,9 @@ void HistoryWidget::updateHistoryGeometry(
|
|||
if (_requestsBar) {
|
||||
newScrollHeight -= _requestsBar->height();
|
||||
}
|
||||
if (_paysStatus) {
|
||||
newScrollHeight -= _paysStatus->bar().height();
|
||||
}
|
||||
if (_contactStatus) {
|
||||
newScrollHeight -= _contactStatus->bar().height();
|
||||
}
|
||||
|
@ -6940,6 +6966,7 @@ void HistoryWidget::botCallbackSent(not_null<HistoryItem*> item) {
|
|||
int HistoryWidget::computeMaxFieldHeight() const {
|
||||
const auto available = height()
|
||||
- _topBar->height()
|
||||
- (_paysStatus ? _paysStatus->bar().height() : 0)
|
||||
- (_contactStatus ? _contactStatus->bar().height() : 0)
|
||||
- (_businessBotStatus ? _businessBotStatus->bar().height() : 0)
|
||||
- (_sponsoredMessageBar ? _sponsoredMessageBar->height() : 0)
|
||||
|
|
|
@ -100,6 +100,7 @@ namespace HistoryView {
|
|||
class StickerToast;
|
||||
class PaidReactionToast;
|
||||
class TopBarWidget;
|
||||
class PaysStatus;
|
||||
class ContactStatus;
|
||||
class BusinessBotStatus;
|
||||
class Element;
|
||||
|
@ -782,6 +783,7 @@ private:
|
|||
|
||||
Webrtc::RecordAvailability _recordAvailability = {};
|
||||
|
||||
std::unique_ptr<HistoryView::PaysStatus> _paysStatus;
|
||||
std::unique_ptr<HistoryView::ContactStatus> _contactStatus;
|
||||
std::unique_ptr<HistoryView::BusinessBotStatus> _businessBotStatus;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "chat_helpers/message_field.h" // PaidSendButtonText
|
||||
#include "core/click_handler_types.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/business/data_business_chatbots.h"
|
||||
|
@ -595,9 +596,9 @@ auto ContactStatus::PeerState(not_null<PeerData*> peer)
|
|||
return {
|
||||
.type = Type::RequestChatInfo,
|
||||
.requestChatName = peer->requestChatTitle(),
|
||||
.requestDate = peer->requestChatDate(),
|
||||
.requestChatIsBroadcast = !!(settings.value
|
||||
& PeerBarSetting::RequestChatIsBroadcast),
|
||||
.requestDate = peer->requestChatDate(),
|
||||
};
|
||||
} else if (settings.value & PeerBarSetting::AutoArchived) {
|
||||
return { Type::UnarchiveOrBlock };
|
||||
|
@ -1131,4 +1132,165 @@ void TopicReopenBar::setupHandler() {
|
|||
});
|
||||
}
|
||||
|
||||
class PaysStatus::Bar final : public Ui::RpWidget {
|
||||
public:
|
||||
Bar(QWidget *parent, not_null<PeerData*> peer);
|
||||
|
||||
void showState(State state);
|
||||
|
||||
[[nodiscard]] rpl::producer<> removeClicks() const;
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
|
||||
not_null<PeerData*> _peer;
|
||||
object_ptr<Ui::FlatLabel> _label;
|
||||
object_ptr<Ui::LinkButton> _remove;
|
||||
rpl::event_stream<> _removeClicks;
|
||||
|
||||
};
|
||||
|
||||
PaysStatus::Bar::Bar(QWidget *parent, not_null<PeerData*> peer)
|
||||
: RpWidget(parent)
|
||||
, _peer(peer)
|
||||
, _label(this, st::paysStatusLabel)
|
||||
, _remove(this, tr::lng_payment_bar_button(tr::now)) {
|
||||
_label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
}
|
||||
|
||||
void PaysStatus::Bar::showState(State state) {
|
||||
_label->setMarkedText(tr::lng_payment_bar_text(
|
||||
tr::now,
|
||||
lt_name,
|
||||
TextWithEntities{ _peer->shortName() },
|
||||
lt_cost,
|
||||
PaidSendButtonText(tr::now, state.perMessage),
|
||||
Ui::Text::WithEntities));
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
||||
rpl::producer<> PaysStatus::Bar::removeClicks() const {
|
||||
return _remove->clicks() | rpl::to_empty;
|
||||
}
|
||||
|
||||
void PaysStatus::Bar::paintEvent(QPaintEvent *e) {
|
||||
QPainter p(this);
|
||||
p.fillRect(e->rect(), st::historyContactStatusButton.bgColor);
|
||||
}
|
||||
|
||||
int PaysStatus::Bar::resizeGetHeight(int newWidth) {
|
||||
const auto skip = st::defaultPeerListItem.photoPosition.y();
|
||||
_label->resizeToWidth(newWidth - skip);
|
||||
_label->moveToLeft(skip, skip, newWidth);
|
||||
_remove->move(
|
||||
(newWidth - _remove->width()) / 2,
|
||||
skip + _label->height() + skip);
|
||||
return _remove->y() + _remove->height() + skip;
|
||||
}
|
||||
|
||||
PaysStatus::PaysStatus(
|
||||
not_null<Window::SessionController*> window,
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<UserData*> user)
|
||||
: _controller(window)
|
||||
, _user(user)
|
||||
, _inner(Ui::CreateChild<Bar>(parent.get(), user))
|
||||
, _bar(parent, object_ptr<Bar>::fromRaw(_inner)) {
|
||||
setupState();
|
||||
setupHandlers();
|
||||
}
|
||||
|
||||
void PaysStatus::setupState() {
|
||||
_user->session().api().requestPeerSettings(_user);
|
||||
|
||||
_user->session().changes().peerFlagsValue(
|
||||
_user,
|
||||
Data::PeerUpdate::Flag::PaysPerMessage
|
||||
) | rpl::start_with_next([=] {
|
||||
_state = State{ _user->paysPerMessage() };
|
||||
if (_state.perMessage > 0) {
|
||||
_inner->showState(_state);
|
||||
_bar.toggleContent(true);
|
||||
} else {
|
||||
_bar.toggleContent(false);
|
||||
}
|
||||
}, _bar.lifetime());
|
||||
}
|
||||
|
||||
void PaysStatus::setupHandlers() {
|
||||
_inner->removeClicks(
|
||||
) | rpl::start_with_next([=] {
|
||||
const auto user = _user;
|
||||
const auto exception = [=](bool refund) {
|
||||
using Flag = MTPaccount_AddNoPaidMessagesException::Flag;
|
||||
const auto api = &user->session().api();
|
||||
api->request(MTPaccount_AddNoPaidMessagesException(
|
||||
MTP_flags(refund ? Flag::f_refund_charged : Flag()),
|
||||
user->inputUser
|
||||
)).done([=] {
|
||||
user->clearPaysPerMessage();
|
||||
}).send();
|
||||
};
|
||||
_controller->show(Box([=](not_null<Ui::GenericBox*> box) {
|
||||
const auto refund = std::make_shared<QPointer<Ui::Checkbox>>();
|
||||
Ui::ConfirmBox(box, {
|
||||
.text = tr::lng_payment_refund_text(
|
||||
tr::now,
|
||||
lt_name,
|
||||
Ui::Text::Bold(user->shortName()),
|
||||
Ui::Text::WithEntities),
|
||||
.confirmed = [=](Fn<void()> close) {
|
||||
exception(*refund && (*refund)->checked());
|
||||
close();
|
||||
},
|
||||
.confirmText = tr::lng_payment_refund_confirm(tr::now),
|
||||
.title = tr::lng_payment_refund_title(tr::now),
|
||||
});
|
||||
const auto paid = box->lifetime().make_state<
|
||||
rpl::variable<int>
|
||||
>();
|
||||
*paid = _paidAlready.value();
|
||||
paid->value() | rpl::start_with_next([=](int already) {
|
||||
if (!already) {
|
||||
delete base::take(*refund);
|
||||
} else if (!*refund) {
|
||||
const auto skip = st::defaultCheckbox.margin.top();
|
||||
*refund = box->addRow(
|
||||
object_ptr<Ui::Checkbox>(
|
||||
box,
|
||||
tr::lng_payment_refund_also(
|
||||
lt_count,
|
||||
paid->value() | tr::to_count()),
|
||||
false,
|
||||
st::defaultCheckbox),
|
||||
st::boxRowPadding + QMargins(0, skip, 0, skip));
|
||||
}
|
||||
}, box->lifetime());
|
||||
|
||||
user->session().api().request(MTPaccount_GetPaidMessagesRevenue(
|
||||
user->inputUser
|
||||
)).done(crl::guard(_inner, [=](
|
||||
const MTPaccount_PaidMessagesRevenue &result) {
|
||||
_paidAlready = result.data().vstars_amount().v;
|
||||
})).send();
|
||||
}));
|
||||
}, _bar.lifetime());
|
||||
}
|
||||
|
||||
void PaysStatus::show() {
|
||||
if (!_shown) {
|
||||
_shown = true;
|
||||
if (_state.perMessage > 0) {
|
||||
_inner->showState(_state);
|
||||
_bar.toggleContent(true);
|
||||
}
|
||||
}
|
||||
_bar.show();
|
||||
}
|
||||
|
||||
void PaysStatus::hide() {
|
||||
_bar.hide();
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -95,9 +95,10 @@ private:
|
|||
RequestChatInfo,
|
||||
};
|
||||
Type type = Type::None;
|
||||
int starsPerMessage = 0;
|
||||
QString requestChatName;
|
||||
bool requestChatIsBroadcast = false;
|
||||
TimeId requestDate = 0;
|
||||
bool requestChatIsBroadcast = false;
|
||||
};
|
||||
|
||||
void setupState(not_null<PeerData*> peer, bool showInForum);
|
||||
|
@ -181,4 +182,38 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class PaysStatus final {
|
||||
public:
|
||||
PaysStatus(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<UserData*> user);
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
|
||||
[[nodiscard]] SlidingBar &bar() {
|
||||
return _bar;
|
||||
}
|
||||
|
||||
private:
|
||||
class Bar;
|
||||
|
||||
struct State {
|
||||
int perMessage = 0;
|
||||
};
|
||||
|
||||
void setupState();
|
||||
void setupHandlers();
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
const not_null<UserData*> _user;
|
||||
rpl::variable<int> _paidAlready;
|
||||
State _state;
|
||||
QPointer<Bar> _inner;
|
||||
SlidingBar _bar;
|
||||
bool _shown = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
Loading…
Add table
Reference in a new issue