mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Subscription status display.
This commit is contained in:
parent
1d7e901b7a
commit
de31c1cf0c
16 changed files with 221 additions and 43 deletions
|
@ -137,6 +137,8 @@ PRIVATE
|
|||
api/api_peer_photo.h
|
||||
api/api_polls.cpp
|
||||
api/api_polls.h
|
||||
api/api_premium.cpp
|
||||
api/api_premium.h
|
||||
api/api_report.cpp
|
||||
api/api_report.h
|
||||
api/api_ringtones.cpp
|
||||
|
|
58
Telegram/SourceFiles/api/api_premium.cpp
Normal file
58
Telegram/SourceFiles/api/api_premium.cpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "api/api_premium.h"
|
||||
|
||||
#include "api/api_text_entities.h"
|
||||
#include "main/main_session.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
namespace Api {
|
||||
|
||||
Premium::Premium(not_null<ApiWrap*> api)
|
||||
: _session(&api->session())
|
||||
, _api(&api->instance()) {
|
||||
crl::on_main(_session, [=] {
|
||||
// You can't use _session->user() in the constructor,
|
||||
// only queued, because it is not constructed yet.
|
||||
Data::AmPremiumValue(
|
||||
_session
|
||||
) | rpl::skip(1) | rpl::start_with_next([=] {
|
||||
reload();
|
||||
}, _session->lifetime());
|
||||
});
|
||||
}
|
||||
|
||||
rpl::producer<TextWithEntities> Premium::statusTextValue() const {
|
||||
return _statusTextUpdates.events_starting_with_copy(
|
||||
_statusText.value_or(TextWithEntities()));
|
||||
}
|
||||
|
||||
void Premium::reload() {
|
||||
if (_statusRequestId) {
|
||||
return;
|
||||
}
|
||||
_statusRequestId = _api.request(MTPhelp_GetPremiumPromo(
|
||||
)).done([=](const MTPhelp_PremiumPromo &result) {
|
||||
_statusRequestId = 0;
|
||||
result.match([&](const MTPDhelp_premiumPromo &data) {
|
||||
auto text = TextWithEntities{
|
||||
qs(data.vstatus_text()),
|
||||
EntitiesFromMTP(_session, data.vstatus_entities().v),
|
||||
};
|
||||
_statusText = text;
|
||||
_statusTextUpdates.fire(std::move(text));
|
||||
});
|
||||
}).fail([=] {
|
||||
_statusRequestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
} // namespace Api
|
37
Telegram/SourceFiles/api/api_premium.h
Normal file
37
Telegram/SourceFiles/api/api_premium.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "mtproto/sender.h"
|
||||
|
||||
class ApiWrap;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Api {
|
||||
|
||||
class Premium final {
|
||||
public:
|
||||
explicit Premium(not_null<ApiWrap*> api);
|
||||
|
||||
void reload();
|
||||
[[nodiscard]] rpl::producer<TextWithEntities> statusTextValue() const;
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
MTP::Sender _api;
|
||||
|
||||
mtpRequestId _statusRequestId = 0;
|
||||
std::optional<TextWithEntities> _statusText;
|
||||
rpl::event_stream<TextWithEntities> _statusTextUpdates;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Api
|
|
@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_unread_things.h"
|
||||
#include "api/api_ringtones.h"
|
||||
#include "api/api_transcribes.h"
|
||||
#include "api/api_premium.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_drafts.h"
|
||||
|
@ -147,7 +148,8 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
|
|||
, _chatParticipants(std::make_unique<Api::ChatParticipants>(this))
|
||||
, _unreadThings(std::make_unique<Api::UnreadThings>(this))
|
||||
, _ringtones(std::make_unique<Api::Ringtones>(this))
|
||||
, _transcribes(std::make_unique<Api::Transcribes>(this)) {
|
||||
, _transcribes(std::make_unique<Api::Transcribes>(this))
|
||||
, _premium(std::make_unique<Api::Premium>(this)) {
|
||||
crl::on_main(session, [=] {
|
||||
// You can't use _session->lifetime() in the constructor,
|
||||
// only queued, because it is not constructed yet.
|
||||
|
@ -4111,3 +4113,7 @@ Api::Ringtones &ApiWrap::ringtones() {
|
|||
Api::Transcribes &ApiWrap::transcribes() {
|
||||
return *_transcribes;
|
||||
}
|
||||
|
||||
Api::Premium &ApiWrap::premium() {
|
||||
return *_premium;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ class ChatParticipants;
|
|||
class UnreadThings;
|
||||
class Ringtones;
|
||||
class Transcribes;
|
||||
class Premium;
|
||||
|
||||
namespace details {
|
||||
|
||||
|
@ -363,6 +364,7 @@ public:
|
|||
[[nodiscard]] Api::UnreadThings &unreadThings();
|
||||
[[nodiscard]] Api::Ringtones &ringtones();
|
||||
[[nodiscard]] Api::Transcribes &transcribes();
|
||||
[[nodiscard]] Api::Premium &premium();
|
||||
|
||||
void updatePrivacyLastSeens();
|
||||
|
||||
|
@ -647,6 +649,7 @@ private:
|
|||
const std::unique_ptr<Api::UnreadThings> _unreadThings;
|
||||
const std::unique_ptr<Api::Ringtones> _ringtones;
|
||||
const std::unique_ptr<Api::Transcribes> _transcribes;
|
||||
const std::unique_ptr<Api::Premium> _premium;
|
||||
|
||||
mtpRequestId _wallPaperRequestId = 0;
|
||||
QString _wallPaperSlug;
|
||||
|
|
|
@ -16,6 +16,7 @@ enum class SharedMediaType : signed char;
|
|||
} // namespace Storage
|
||||
|
||||
namespace Ui {
|
||||
class RoundRect;
|
||||
class ScrollArea;
|
||||
class InputField;
|
||||
struct ScrollToRequest;
|
||||
|
@ -67,7 +68,10 @@ public:
|
|||
int topDelta);
|
||||
void applyAdditionalScroll(int additionalScroll);
|
||||
int scrollTillBottom(int forHeight) const;
|
||||
rpl::producer<int> scrollTillBottomChanges() const;
|
||||
[[nodiscard]] rpl::producer<int> scrollTillBottomChanges() const;
|
||||
[[nodiscard]] virtual const Ui::RoundRect *bottomSkipRounding() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Float player interface.
|
||||
bool floatPlayerHandleWheelEvent(QEvent *e);
|
||||
|
|
|
@ -306,7 +306,6 @@ QRect LayerWidget::countGeometry(int newWidth) {
|
|||
if (_contentTillBottom) {
|
||||
contentHeight += contentBottom;
|
||||
}
|
||||
const auto bottomPadding = _tillBottom ? 0 : contentBottom;
|
||||
_content->updateGeometry({
|
||||
contentLeft,
|
||||
contentTop,
|
||||
|
@ -330,11 +329,18 @@ void LayerWidget::paintEvent(QPaintEvent *e) {
|
|||
const auto radius = st::boxRadius;
|
||||
auto parts = RectPart::None | 0;
|
||||
if (!_tillBottom) {
|
||||
if (clip.intersects({ 0, height() - radius, width(), radius })) {
|
||||
parts |= RectPart::FullBottom;
|
||||
const auto bottom = QRect{ 0, height() - radius, width(), radius };
|
||||
if (clip.intersects(bottom)) {
|
||||
if (const auto rounding = _content->bottomSkipRounding()) {
|
||||
rounding->paint(p, rect(), RectPart::FullBottom);
|
||||
} else {
|
||||
parts |= RectPart::FullBottom;
|
||||
}
|
||||
}
|
||||
} else if (!_contentTillBottom) {
|
||||
p.fillRect(0, height() - radius, width(), radius, st::boxBg);
|
||||
const auto rounding = _content->bottomSkipRounding();
|
||||
const auto &color = rounding ? rounding->color() : st::boxBg;
|
||||
p.fillRect(0, height() - radius, width(), radius, color);
|
||||
}
|
||||
if (_content->animatingShow()) {
|
||||
if (clip.intersects({ 0, 0, width(), radius })) {
|
||||
|
|
|
@ -1156,6 +1156,10 @@ rpl::producer<bool> WrapWidget::grabbingForExpanding() const {
|
|||
return _grabbingForExpanding.value();
|
||||
}
|
||||
|
||||
const Ui::RoundRect *WrapWidget::bottomSkipRounding() const {
|
||||
return _content->bottomSkipRounding();
|
||||
}
|
||||
|
||||
bool WrapWidget::hasBackButton() const {
|
||||
return (wrap() == Wrap::Narrow || hasStackHistory());
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ class FadeShadow;
|
|||
class PlainShadow;
|
||||
class PopupMenu;
|
||||
class IconButton;
|
||||
class RoundRect;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
|
@ -129,6 +130,7 @@ public:
|
|||
[[nodiscard]] int scrollTillBottom(int forHeight) const;
|
||||
[[nodiscard]] rpl::producer<int> scrollTillBottomChanges() const;
|
||||
[[nodiscard]] rpl::producer<bool> grabbingForExpanding() const;
|
||||
[[nodiscard]] const Ui::RoundRect *bottomSkipRounding() const;
|
||||
|
||||
~WrapWidget();
|
||||
|
||||
|
|
|
@ -213,6 +213,10 @@ void Widget::setInnerFocus() {
|
|||
_inner->setInnerFocus();
|
||||
}
|
||||
|
||||
const Ui::RoundRect *Widget::bottomSkipRounding() const {
|
||||
return _inner->bottomSkipRounding();
|
||||
}
|
||||
|
||||
rpl::producer<bool> Widget::desiredShadowVisibility() const {
|
||||
return (_type == ::Settings::Main::Id()
|
||||
|| _type == ::Settings::Information::Id())
|
||||
|
|
|
@ -72,6 +72,7 @@ public:
|
|||
|
||||
void showFinished() override;
|
||||
void setInnerFocus() override;
|
||||
const Ui::RoundRect *bottomSkipRounding() const override;
|
||||
|
||||
rpl::producer<bool> desiredShadowVisibility() const override;
|
||||
|
||||
|
|
|
@ -455,3 +455,4 @@ settingsPremiumAboutTextStyle: TextStyle(defaultTextStyle) {
|
|||
font: font(12px);
|
||||
lineHeight: 18px;
|
||||
}
|
||||
settingsPremiumStatusPadding: margins(22px, 8px, 22px, 2px);
|
||||
|
|
|
@ -93,6 +93,9 @@ public:
|
|||
virtual void setInnerFocus() {
|
||||
setFocus();
|
||||
}
|
||||
[[nodiscard]] virtual const Ui::RoundRect *bottomSkipRounding() const {
|
||||
return nullptr;
|
||||
}
|
||||
[[nodiscard]] virtual QPointer<Ui::RpWidget> createPinnedToTop(
|
||||
not_null<QWidget*> parent) {
|
||||
return nullptr;
|
||||
|
|
|
@ -47,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_cloud_password.h"
|
||||
#include "api/api_global_privacy.h"
|
||||
#include "api/api_sensitive_content.h"
|
||||
#include "api/api_premium.h"
|
||||
#include "info/profile/info_profile_values.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
@ -558,6 +559,9 @@ Main::Main(
|
|||
: Section(parent)
|
||||
, _controller(controller) {
|
||||
setupContent(controller);
|
||||
if (_controller->session().premium()) {
|
||||
_controller->session().api().premium().reload();
|
||||
}
|
||||
}
|
||||
|
||||
rpl::producer<QString> Main::title() {
|
||||
|
|
|
@ -35,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "window/window_session_controller.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "apiwrap.h"
|
||||
#include "api/api_premium.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
#include "styles/style_info.h"
|
||||
|
@ -164,6 +165,43 @@ using Order = std::vector<QString>;
|
|||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] not_null<Ui::RpWidget*> CreateSubscribeButton(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
Fn<void()> callback) {
|
||||
const auto result = Ui::CreateChild<Ui::GradientButton>(
|
||||
parent.get(),
|
||||
Ui::Premium::ButtonGradientStops());
|
||||
|
||||
result->setClickedCallback(std::move(callback));
|
||||
|
||||
const auto &st = st::premiumPreviewBox.button;
|
||||
result->resize(parent->width(), st.height);
|
||||
|
||||
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
||||
result,
|
||||
tr::lng_premium_summary_button(tr::now, lt_cost, "$5"),
|
||||
st::premiumPreviewButtonLabel);
|
||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
rpl::combine(
|
||||
result->widthValue(),
|
||||
label->widthValue()
|
||||
) | rpl::start_with_next([=](int outer, int width) {
|
||||
label->moveToLeft(
|
||||
(outer - width) / 2,
|
||||
st::premiumPreviewBox.button.textTop,
|
||||
outer);
|
||||
}, label->lifetime());
|
||||
|
||||
parent->widthValue(
|
||||
) | rpl::start_with_next([=](int width) {
|
||||
const auto padding = st::settingsPremiumButtonPadding;
|
||||
result->resizeToWidth(width - padding.left() - padding.right());
|
||||
result->moveToLeft(padding.left(), padding.top(), width);
|
||||
}, result->lifetime());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SendAppLog(
|
||||
not_null<Main::Session*> session,
|
||||
const QString &type,
|
||||
|
@ -583,6 +621,7 @@ public:
|
|||
not_null<Ui::RpWidget*> parent) override;
|
||||
|
||||
[[nodiscard]] bool hasFlexibleTopBar() const override;
|
||||
[[nodiscard]] const Ui::RoundRect *bottomSkipRounding() const override;
|
||||
|
||||
void setStepDataReference(std::any &data) override;
|
||||
|
||||
|
@ -598,6 +637,7 @@ private:
|
|||
base::unique_qptr<Ui::IconButton> _close;
|
||||
rpl::variable<bool> _backToggles;
|
||||
rpl::variable<Info::Wrap> _wrap;
|
||||
std::optional<Ui::RoundRect> _bottomSkipRounding;
|
||||
|
||||
rpl::event_stream<> _showBack;
|
||||
|
||||
|
@ -610,6 +650,7 @@ Premium::Premium(
|
|||
, _controller(controller)
|
||||
, _ref(ResolveRef(controller->premiumRef())) {
|
||||
setupContent();
|
||||
_controller->session().api().premium().reload();
|
||||
}
|
||||
|
||||
rpl::producer<QString> Premium::title() {
|
||||
|
@ -620,6 +661,10 @@ bool Premium::hasFlexibleTopBar() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
const Ui::RoundRect *Premium::bottomSkipRounding() const {
|
||||
return _bottomSkipRounding ? &*_bottomSkipRounding : nullptr;
|
||||
}
|
||||
|
||||
rpl::producer<> Premium::sectionShowBack() {
|
||||
return _showBack.events();
|
||||
}
|
||||
|
@ -763,8 +808,6 @@ void Premium::setupContent() {
|
|||
st::aboutLabel),
|
||||
st::boxRowPadding);
|
||||
AddSkip(content, stDefault.padding.top() + stDefault.padding.bottom());
|
||||
#else
|
||||
AddSkip(content, stDefault.padding.bottom());
|
||||
#endif
|
||||
|
||||
Ui::ResizeFitChild(this, content);
|
||||
|
@ -835,51 +878,51 @@ QPointer<Ui::RpWidget> Premium::createPinnedToBottom(
|
|||
not_null<Ui::RpWidget*> parent) {
|
||||
const auto content = Ui::CreateChild<Ui::RpWidget>(parent.get());
|
||||
|
||||
auto result = object_ptr<Ui::GradientButton>(
|
||||
content,
|
||||
Ui::Premium::ButtonGradientStops());
|
||||
const auto raw = result.data();
|
||||
|
||||
raw->setClickedCallback([=] {
|
||||
const auto button = CreateSubscribeButton(content, [=] {
|
||||
SendScreenAccept(_controller);
|
||||
StartPremiumPayment(_controller, _ref);
|
||||
});
|
||||
|
||||
const auto &st = st::premiumPreviewBox.button;
|
||||
raw->resize(content->width(), st.height);
|
||||
|
||||
const auto label = Ui::CreateChild<Ui::FlatLabel>(
|
||||
raw,
|
||||
tr::lng_premium_summary_button(tr::now, lt_cost, "$5"),
|
||||
st::premiumPreviewButtonLabel);
|
||||
label->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
rpl::combine(
|
||||
raw->widthValue(),
|
||||
label->widthValue()
|
||||
) | rpl::start_with_next([=](int outer, int width) {
|
||||
label->moveToLeft(
|
||||
(outer - width) / 2,
|
||||
st::premiumPreviewBox.button.textTop,
|
||||
outer);
|
||||
}, label->lifetime());
|
||||
|
||||
auto text = _controller->session().api().premium().statusTextValue();
|
||||
const auto status = Ui::CreateChild<Ui::DividerLabel>(
|
||||
content,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
content,
|
||||
rpl::duplicate(text),
|
||||
st::boxDividerLabel),
|
||||
st::settingsPremiumStatusPadding,
|
||||
RectPart::Top);
|
||||
content->widthValue(
|
||||
) | rpl::start_with_next([=](int width) {
|
||||
const auto padding = st::settingsPremiumButtonPadding;
|
||||
raw->resizeToWidth(width - padding.left() - padding.right());
|
||||
}, raw->lifetime());
|
||||
status->resizeToWidth(width);
|
||||
}, status->lifetime());
|
||||
|
||||
rpl::combine(
|
||||
raw->heightValue(),
|
||||
button->heightValue(),
|
||||
status->heightValue(),
|
||||
std::move(text),
|
||||
Data::AmPremiumValue(&_controller->session())
|
||||
) | rpl::start_with_next([=](int height, bool premium) {
|
||||
) | rpl::start_with_next([=](
|
||||
int buttonHeight,
|
||||
int statusHeight,
|
||||
const TextWithEntities &text,
|
||||
bool premium) {
|
||||
const auto padding = st::settingsPremiumButtonPadding;
|
||||
const auto finalHeight = premium
|
||||
const auto finalHeight = !premium
|
||||
? (padding.top() + buttonHeight + padding.bottom())
|
||||
: text.text.isEmpty()
|
||||
? 0
|
||||
: (padding.top() + height + padding.bottom());
|
||||
: statusHeight;
|
||||
content->resize(content->width(), finalHeight);
|
||||
raw->moveToLeft(padding.left(), padding.top());
|
||||
}, raw->lifetime());
|
||||
button->moveToLeft(padding.left(), padding.top());
|
||||
status->moveToLeft(0, 0);
|
||||
button->setVisible(!premium);
|
||||
status->setVisible(premium && !text.text.isEmpty());
|
||||
if (!premium || text.text.isEmpty()) {
|
||||
_bottomSkipRounding.reset();
|
||||
} else if (!_bottomSkipRounding) {
|
||||
_bottomSkipRounding.emplace(st::boxRadius, st::boxDividerBg);
|
||||
}
|
||||
}, button->lifetime());
|
||||
|
||||
return Ui::MakeWeak(not_null<Ui::RpWidget*>{ content });
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 094c2ea9669dbcb9547b7868d9de0e00fc04844d
|
||||
Subproject commit b802516ca73c9b20103b5e98d940490dfcc7fea8
|
Loading…
Add table
Reference in a new issue