mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-24 09:16:57 +00:00
Support blocking progress in payment panel.
This commit is contained in:
parent
52b5c4cbe0
commit
0ead0879d7
@ -155,6 +155,7 @@ CheckoutProcess::CheckoutProcess(
|
||||
panelCancelEdit();
|
||||
}, _panel->lifetime());
|
||||
showForm();
|
||||
_panel->toggleProgress(true);
|
||||
|
||||
if (mode == Mode::Payment) {
|
||||
_session->api().passwordState(
|
||||
@ -180,7 +181,9 @@ not_null<Ui::PanelDelegate*> CheckoutProcess::panelDelegate() {
|
||||
}
|
||||
|
||||
void CheckoutProcess::handleFormUpdate(const FormUpdate &update) {
|
||||
v::match(update, [&](const FormReady &) {
|
||||
v::match(update, [&](const ToggleProgress &data) {
|
||||
_panel->toggleProgress(data.shown);
|
||||
}, [&](const FormReady &) {
|
||||
performInitialSilentValidation();
|
||||
if (!_initialSilentValidation) {
|
||||
showForm();
|
||||
|
@ -170,6 +170,14 @@ void Form::fillInvoiceFromMessage() {
|
||||
}
|
||||
}
|
||||
|
||||
void Form::showProgress() {
|
||||
_updates.fire(ToggleProgress{ true });
|
||||
}
|
||||
|
||||
void Form::hideProgress() {
|
||||
_updates.fire(ToggleProgress{ false });
|
||||
}
|
||||
|
||||
void Form::loadThumbnail(not_null<PhotoData*> photo) {
|
||||
Expects(!_thumbnailLoadProcess);
|
||||
|
||||
@ -251,29 +259,35 @@ QImage Form::prepareEmptyThumbnail() const {
|
||||
}
|
||||
|
||||
void Form::requestForm() {
|
||||
showProgress();
|
||||
_api.request(MTPpayments_GetPaymentForm(
|
||||
MTP_flags(MTPpayments_GetPaymentForm::Flag::f_theme_params),
|
||||
_peer->input,
|
||||
MTP_int(_msgId),
|
||||
MTP_dataJSON(MTP_bytes(ThemeParams()))
|
||||
)).done([=](const MTPpayments_PaymentForm &result) {
|
||||
hideProgress();
|
||||
result.match([&](const auto &data) {
|
||||
processForm(data);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
hideProgress();
|
||||
_updates.fire(Error{ Error::Type::Form, error.type() });
|
||||
}).send();
|
||||
}
|
||||
|
||||
void Form::requestReceipt() {
|
||||
showProgress();
|
||||
_api.request(MTPpayments_GetPaymentReceipt(
|
||||
_peer->input,
|
||||
MTP_int(_msgId)
|
||||
)).done([=](const MTPpayments_PaymentReceipt &result) {
|
||||
hideProgress();
|
||||
result.match([&](const auto &data) {
|
||||
processReceipt(data);
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
hideProgress();
|
||||
_updates.fire(Error{ Error::Type::Form, error.type() });
|
||||
}).send();
|
||||
}
|
||||
@ -551,6 +565,7 @@ void Form::submit() {
|
||||
}
|
||||
|
||||
using Flag = MTPpayments_SendPaymentForm::Flag;
|
||||
showProgress();
|
||||
_api.request(MTPpayments_SendPaymentForm(
|
||||
MTP_flags((_requestedInformationId.isEmpty()
|
||||
? Flag(0)
|
||||
@ -576,12 +591,14 @@ void Form::submit() {
|
||||
MTP_bytes(password))),
|
||||
MTP_long(_invoice.tipsSelected)
|
||||
)).done([=](const MTPpayments_PaymentResult &result) {
|
||||
hideProgress();
|
||||
result.match([&](const MTPDpayments_paymentResult &data) {
|
||||
_updates.fire(PaymentFinished{ data.vupdates() });
|
||||
}, [&](const MTPDpayments_paymentVerificationNeeded &data) {
|
||||
_updates.fire(VerificationNeeded{ qs(data.vurl()) });
|
||||
});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
hideProgress();
|
||||
_updates.fire(Error{ Error::Type::Send, error.type() });
|
||||
}).send();
|
||||
}
|
||||
@ -612,6 +629,7 @@ void Form::validateInformation(const Ui::RequestedInformation &information) {
|
||||
if (_validatedInformation == information) {
|
||||
return;
|
||||
}
|
||||
hideProgress();
|
||||
_api.request(base::take(_validateRequestId)).cancel();
|
||||
}
|
||||
_validatedInformation = information;
|
||||
@ -625,6 +643,7 @@ void Form::validateInformation(const Ui::RequestedInformation &information) {
|
||||
Assert(!_invoice.isEmailRequested || !information.email.isEmpty());
|
||||
Assert(!_invoice.isPhoneRequested || !information.phone.isEmpty());
|
||||
|
||||
showProgress();
|
||||
using Flag = MTPpayments_ValidateRequestedInfo::Flag;
|
||||
_validateRequestId = _api.request(MTPpayments_ValidateRequestedInfo(
|
||||
MTP_flags(information.save ? Flag::f_save : Flag(0)),
|
||||
@ -632,6 +651,7 @@ void Form::validateInformation(const Ui::RequestedInformation &information) {
|
||||
MTP_int(_msgId),
|
||||
Serialize(information)
|
||||
)).done([=](const MTPpayments_ValidatedRequestedInfo &result) {
|
||||
hideProgress();
|
||||
_validateRequestId = 0;
|
||||
const auto oldSelectedId = _shippingOptions.selectedId;
|
||||
result.match([&](const MTPDpayments_validatedRequestedInfo &data) {
|
||||
@ -654,6 +674,7 @@ void Form::validateInformation(const Ui::RequestedInformation &information) {
|
||||
}
|
||||
_updates.fire(ValidateFinished{});
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
hideProgress();
|
||||
_validateRequestId = 0;
|
||||
_updates.fire(Error{ Error::Type::Validate, error.type() });
|
||||
}).send();
|
||||
@ -798,9 +819,11 @@ void Form::validateCard(
|
||||
.addressZip = details.addressZip,
|
||||
.addressCountry = details.addressCountry,
|
||||
};
|
||||
showProgress();
|
||||
_stripe->createTokenWithCard(std::move(card), crl::guard(this, [=](
|
||||
Stripe::Token token,
|
||||
Stripe::Error error) {
|
||||
hideProgress();
|
||||
_stripe = nullptr;
|
||||
|
||||
if (error) {
|
||||
@ -846,9 +869,11 @@ void Form::validateCard(
|
||||
.addressZip = details.addressZip,
|
||||
.addressCountry = details.addressCountry,
|
||||
};
|
||||
showProgress();
|
||||
_smartglocal->createTokenWithCard(std::move(card), crl::guard(this, [=](
|
||||
SmartGlocal::Token token,
|
||||
SmartGlocal::Error error) {
|
||||
hideProgress();
|
||||
_smartglocal = nullptr;
|
||||
|
||||
if (error) {
|
||||
|
@ -116,6 +116,9 @@ struct PaymentMethod {
|
||||
Ui::PaymentMethodDetails ui;
|
||||
};
|
||||
|
||||
struct ToggleProgress {
|
||||
bool shown = true;
|
||||
};
|
||||
struct FormReady {};
|
||||
struct ThumbnailUpdated {
|
||||
QImage thumbnail;
|
||||
@ -157,6 +160,7 @@ struct Error {
|
||||
};
|
||||
|
||||
struct FormUpdate : std::variant<
|
||||
ToggleProgress,
|
||||
FormReady,
|
||||
ThumbnailUpdated,
|
||||
ValidateFinished,
|
||||
@ -209,6 +213,8 @@ public:
|
||||
|
||||
private:
|
||||
void fillInvoiceFromMessage();
|
||||
void showProgress();
|
||||
void hideProgress();
|
||||
|
||||
void loadThumbnail(not_null<PhotoData*> photo);
|
||||
[[nodiscard]] QImage prepareGoodThumbnail(
|
||||
|
@ -129,6 +129,10 @@ bool FormSummary::showCriticalError(const TextWithEntities &text) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int FormSummary::contentHeight() const {
|
||||
return _invoice ? _scroll->height() : _layout->height();
|
||||
}
|
||||
|
||||
void FormSummary::updateThumbnail(const QImage &thumbnail) {
|
||||
_invoice.cover.thumbnail = thumbnail;
|
||||
_thumbnails.fire_copy(thumbnail);
|
||||
|
@ -40,6 +40,7 @@ public:
|
||||
[[nodiscard]] rpl::producer<int> scrollTopValue() const;
|
||||
|
||||
bool showCriticalError(const TextWithEntities &text);
|
||||
[[nodiscard]] int contentHeight() const;
|
||||
|
||||
private:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "ui/boxes/single_choice_box.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "webview/webview_embed.h"
|
||||
#include "webview/webview_interface.h"
|
||||
@ -25,6 +26,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
namespace Payments::Ui {
|
||||
namespace {
|
||||
|
||||
constexpr auto kProgressDuration = crl::time(200);
|
||||
constexpr auto kProgressOpacity = 0.3;
|
||||
|
||||
} // namespace
|
||||
|
||||
struct Panel::Progress {
|
||||
Progress(QWidget *parent, Fn<QRect()> rect);
|
||||
|
||||
RpWidget widget;
|
||||
InfiniteRadialAnimation animation;
|
||||
Animations::Simple shownAnimation;
|
||||
bool shown = true;
|
||||
rpl::lifetime geometryLifetime;
|
||||
};
|
||||
|
||||
Panel::Progress::Progress(QWidget *parent, Fn<QRect()> rect)
|
||||
: widget(parent)
|
||||
, animation(
|
||||
[=] { if (!anim::Disabled()) widget.update(rect()); },
|
||||
st::boxLoadingAnimation) {
|
||||
}
|
||||
|
||||
Panel::Panel(not_null<PanelDelegate*> delegate)
|
||||
: _delegate(delegate)
|
||||
@ -45,6 +69,7 @@ Panel::Panel(not_null<PanelDelegate*> delegate)
|
||||
|
||||
Panel::~Panel() {
|
||||
// Destroy _widget before _webview.
|
||||
_progress = nullptr;
|
||||
_widget = nullptr;
|
||||
}
|
||||
|
||||
@ -52,6 +77,139 @@ void Panel::requestActivate() {
|
||||
_widget->showAndActivate();
|
||||
}
|
||||
|
||||
void Panel::toggleProgress(bool shown) {
|
||||
if (!_progress) {
|
||||
if (!shown) {
|
||||
return;
|
||||
}
|
||||
_progress = std::make_unique<Progress>(
|
||||
_widget.get(),
|
||||
[=] { return progressRect(); });
|
||||
_progress->widget.paintRequest(
|
||||
) | rpl::start_with_next([=](QRect clip) {
|
||||
auto p = QPainter(&_progress->widget);
|
||||
p.setOpacity(
|
||||
_progress->shownAnimation.value(_progress->shown ? 1. : 0.));
|
||||
auto thickness = _webviewBottom
|
||||
? st::boxLoadingAnimation.thickness
|
||||
: (st::boxLoadingAnimation.thickness * 2);
|
||||
if (progressWithBackground()) {
|
||||
auto color = st::windowBg->c;
|
||||
color.setAlphaF(kProgressOpacity);
|
||||
p.fillRect(clip, color);
|
||||
}
|
||||
const auto rect = progressRect().marginsRemoved(
|
||||
{ thickness, thickness, thickness, thickness });
|
||||
InfiniteRadialAnimation::Draw(
|
||||
p,
|
||||
_progress->animation.computeState(),
|
||||
rect.topLeft(),
|
||||
rect.size() - QSize(),
|
||||
_progress->widget.width(),
|
||||
st::boxLoadingAnimation.color,
|
||||
thickness);
|
||||
}, _progress->widget.lifetime());
|
||||
_progress->widget.show();
|
||||
_progress->animation.start();
|
||||
} else if (_progress->shown == shown) {
|
||||
return;
|
||||
}
|
||||
const auto callback = [=] {
|
||||
if (!_progress->shownAnimation.animating() && !_progress->shown) {
|
||||
_progress = nullptr;
|
||||
} else {
|
||||
_progress->widget.update();
|
||||
}
|
||||
};
|
||||
_progress->shown = shown;
|
||||
_progress->shownAnimation.start(
|
||||
callback,
|
||||
shown ? 0. : 1.,
|
||||
shown ? 1. : 0.,
|
||||
kProgressDuration);
|
||||
if (shown) {
|
||||
setupProgressGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
bool Panel::progressWithBackground() const {
|
||||
return (_progress->widget.width() == _widget->innerGeometry().width());
|
||||
}
|
||||
|
||||
QRect Panel::progressRect() const {
|
||||
const auto rect = _progress->widget.rect();
|
||||
if (!progressWithBackground()) {
|
||||
return rect;
|
||||
}
|
||||
const auto size = st::defaultBoxButton.height;
|
||||
return QRect(
|
||||
rect.x() + (rect.width() - size) / 2,
|
||||
rect.y() + (rect.height() - size) / 2,
|
||||
size,
|
||||
size);
|
||||
}
|
||||
|
||||
void Panel::setupProgressGeometry() {
|
||||
if (!_progress || !_progress->shown) {
|
||||
return;
|
||||
}
|
||||
_progress->geometryLifetime.destroy();
|
||||
if (_webviewBottom) {
|
||||
_webviewBottom->geometryValue(
|
||||
) | rpl::start_with_next([=](QRect bottom) {
|
||||
const auto height = bottom.height();
|
||||
const auto size = height
|
||||
- st::layerBox.buttonPadding.top()
|
||||
- st::layerBox.buttonPadding.bottom();
|
||||
const auto inner = _widget->innerGeometry();
|
||||
const auto right = inner.x() + inner.width();
|
||||
const auto top = inner.y() + inner.height() - height;
|
||||
// This doesn't work, because first we get the correct bottom
|
||||
// geometry and after that we get the previous event (which
|
||||
// triggered the 'fire' of correct geometry before getting here).
|
||||
//const auto right = bottom.x() + bottom.width();
|
||||
//const auto top = bottom.y();
|
||||
_progress->widget.setGeometry(
|
||||
right - size - st::layerBox.buttonPadding.right(),
|
||||
top + st::layerBox.buttonPadding.top(),
|
||||
size,
|
||||
size);
|
||||
}, _progress->geometryLifetime);
|
||||
} else if (_weakFormSummary) {
|
||||
_weakFormSummary->sizeValue(
|
||||
) | rpl::start_with_next([=](QSize form) {
|
||||
const auto full = _widget->innerGeometry();
|
||||
const auto size = st::defaultBoxButton.height;
|
||||
const auto inner = _weakFormSummary->contentHeight();
|
||||
const auto left = full.height() - inner;
|
||||
if (left >= 2 * size) {
|
||||
_progress->widget.setGeometry(
|
||||
full.x() + (full.width() - size) / 2,
|
||||
full.y() + inner + (left - size) / 2,
|
||||
size,
|
||||
size);
|
||||
} else {
|
||||
_progress->widget.setGeometry(full);
|
||||
}
|
||||
}, _progress->geometryLifetime);
|
||||
} else if (_weakEditInformation) {
|
||||
_weakEditInformation->geometryValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
_progress->widget.setGeometry(_widget->innerGeometry());
|
||||
}, _progress->geometryLifetime);
|
||||
} else if (_weakEditCard) {
|
||||
_weakEditCard->geometryValue(
|
||||
) | rpl::start_with_next([=] {
|
||||
_progress->widget.setGeometry(_widget->innerGeometry());
|
||||
}, _progress->geometryLifetime);
|
||||
}
|
||||
_progress->widget.show();
|
||||
_progress->widget.raise();
|
||||
if (_progress->shown) {
|
||||
_progress->widget.setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void Panel::showForm(
|
||||
const Invoice &invoice,
|
||||
const RequestedInformation ¤t,
|
||||
@ -83,6 +241,7 @@ void Panel::showForm(
|
||||
_widget->showInner(std::move(form));
|
||||
_widget->setBackAllowed(false);
|
||||
_formScrollTop = _weakFormSummary->scrollTopValue();
|
||||
setupProgressGeometry();
|
||||
}
|
||||
|
||||
void Panel::updateFormThumbnail(const QImage &thumbnail) {
|
||||
@ -106,6 +265,7 @@ void Panel::showEditInformation(
|
||||
_widget->showInner(std::move(edit));
|
||||
_widget->setBackAllowed(true);
|
||||
_weakEditInformation->setFocusFast(field);
|
||||
setupProgressGeometry();
|
||||
}
|
||||
|
||||
void Panel::showInformationError(
|
||||
@ -278,6 +438,7 @@ bool Panel::showWebview(
|
||||
if (!_webview && !createWebview()) {
|
||||
return false;
|
||||
}
|
||||
toggleProgress(true);
|
||||
_widget->destroyLayer();
|
||||
_webview->navigate(url);
|
||||
_widget->setBackAllowed(allowBack);
|
||||
@ -347,8 +508,15 @@ bool Panel::createWebview() {
|
||||
_delegate->panelWebviewMessage(message, save);
|
||||
});
|
||||
|
||||
raw->setNavigationHandler([=](const QString &uri) {
|
||||
return _delegate->panelWebviewNavigationAttempt(uri);
|
||||
raw->setNavigationStartHandler([=](const QString &uri) {
|
||||
if (!_delegate->panelWebviewNavigationAttempt(uri)) {
|
||||
return false;
|
||||
}
|
||||
toggleProgress(true);
|
||||
return true;
|
||||
});
|
||||
raw->setNavigationDoneHandler([=](bool success) {
|
||||
toggleProgress(false);
|
||||
});
|
||||
|
||||
raw->init(R"(
|
||||
@ -361,6 +529,9 @@ postEvent: function(eventType, eventData) {
|
||||
};)");
|
||||
|
||||
_widget->showInner(std::move(container));
|
||||
|
||||
setupProgressGeometry();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -452,6 +623,7 @@ void Panel::showEditCard(
|
||||
_widget->showInner(std::move(edit));
|
||||
_widget->setBackAllowed(true);
|
||||
_weakEditCard->setFocusFast(field);
|
||||
setupProgressGeometry();
|
||||
}
|
||||
|
||||
void Panel::showCardError(
|
||||
@ -494,6 +666,7 @@ void Panel::showToast(const TextWithEntities &text) {
|
||||
}
|
||||
|
||||
void Panel::showCriticalError(const TextWithEntities &text) {
|
||||
toggleProgress(false);
|
||||
if (!_weakFormSummary || !_weakFormSummary->showCriticalError(text)) {
|
||||
auto error = base::make_unique_q<PaddingWrap<FlatLabel>>(
|
||||
_widget.get(),
|
||||
|
@ -43,6 +43,7 @@ public:
|
||||
~Panel();
|
||||
|
||||
void requestActivate();
|
||||
void toggleProgress(bool shown);
|
||||
|
||||
void showForm(
|
||||
const Invoice &invoice,
|
||||
@ -86,16 +87,23 @@ public:
|
||||
[[nodiscard]] rpl::lifetime &lifetime();
|
||||
|
||||
private:
|
||||
struct Progress;
|
||||
|
||||
bool createWebview();
|
||||
void showWebviewError(
|
||||
const QString &text,
|
||||
const Webview::Available &information);
|
||||
void setTitle(rpl::producer<QString> title);
|
||||
|
||||
[[nodiscard]] bool progressWithBackground() const;
|
||||
[[nodiscard]] QRect progressRect() const;
|
||||
void setupProgressGeometry();
|
||||
|
||||
const not_null<PanelDelegate*> _delegate;
|
||||
std::unique_ptr<SeparatePanel> _widget;
|
||||
std::unique_ptr<Webview::Window> _webview;
|
||||
std::unique_ptr<RpWidget> _webviewBottom;
|
||||
std::unique_ptr<Progress> _progress;
|
||||
QPointer<Checkbox> _saveWebviewInformation;
|
||||
QPointer<FormSummary> _weakFormSummary;
|
||||
rpl::variable<int> _formScrollTop;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit c1548226d49db23f68bbf35f34cc820171aed65c
|
||||
Subproject commit fa6828443c71932de74ec2a0ffa5f3e8d3bc894c
|
Loading…
Reference in New Issue
Block a user