mirror of https://github.com/procxx/kepka.git
Show scans/selfie saving errors.
This commit is contained in:
parent
f8b2e474b9
commit
e7ce4ca10a
|
@ -1583,6 +1583,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_passport_confirm_phone" = "We've sent an SMS with a confirmation code to your phone {phone}.";
|
"lng_passport_confirm_phone" = "We've sent an SMS with a confirmation code to your phone {phone}.";
|
||||||
"lng_passport_confirm_email" = "We've sent a confirmation code to your email {email}.";
|
"lng_passport_confirm_email" = "We've sent a confirmation code to your email {email}.";
|
||||||
"lng_passport_sure_cancel" = "If you continue your changes will be lost.";
|
"lng_passport_sure_cancel" = "If you continue your changes will be lost.";
|
||||||
|
"lng_passport_scans_limit_reached" = "Scans limit reached.";
|
||||||
|
|
||||||
// Wnd specific
|
// Wnd specific
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,11 @@ rpl::producer<bool> Button::toggledValue() const {
|
||||||
return rpl::never<bool>();
|
return rpl::never<bool>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Button::setColorOverride(base::optional<QColor> textColorOverride) {
|
||||||
|
_textColorOverride = textColorOverride;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void Button::paintEvent(QPaintEvent *e) {
|
void Button::paintEvent(QPaintEvent *e) {
|
||||||
Painter p(this);
|
Painter p(this);
|
||||||
|
|
||||||
|
@ -69,7 +74,11 @@ void Button::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
auto outerw = width();
|
auto outerw = width();
|
||||||
p.setFont(_st.font);
|
p.setFont(_st.font);
|
||||||
p.setPen(paintOver ? _st.textFgOver : _st.textFg);
|
p.setPen(_textColorOverride
|
||||||
|
? QPen(*_textColorOverride)
|
||||||
|
: paintOver
|
||||||
|
? _st.textFgOver
|
||||||
|
: _st.textFg);
|
||||||
p.drawTextLeft(
|
p.drawTextLeft(
|
||||||
_st.padding.left(),
|
_st.padding.left(),
|
||||||
_st.padding.top(),
|
_st.padding.top(),
|
||||||
|
|
|
@ -29,6 +29,8 @@ public:
|
||||||
Button *toggleOn(rpl::producer<bool> &&toggled);
|
Button *toggleOn(rpl::producer<bool> &&toggled);
|
||||||
rpl::producer<bool> toggledValue() const;
|
rpl::producer<bool> toggledValue() const;
|
||||||
|
|
||||||
|
void setColorOverride(base::optional<QColor> textColorOverride);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int resizeGetHeight(int newWidth) override;
|
int resizeGetHeight(int newWidth) override;
|
||||||
void onStateChanged(
|
void onStateChanged(
|
||||||
|
@ -48,6 +50,7 @@ private:
|
||||||
int _originalWidth = 0;
|
int _originalWidth = 0;
|
||||||
int _textWidth = 0;
|
int _textWidth = 0;
|
||||||
std::unique_ptr<Ui::ToggleView> _toggle;
|
std::unique_ptr<Ui::ToggleView> _toggle;
|
||||||
|
base::optional<QColor> _textColorOverride;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Passport {
|
namespace Passport {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kDocumentScansLimit = 20;
|
||||||
|
|
||||||
QImage ReadImage(bytes::const_span buffer) {
|
QImage ReadImage(bytes::const_span buffer) {
|
||||||
return App::readImage(QByteArray::fromRawData(
|
return App::readImage(QByteArray::fromRawData(
|
||||||
reinterpret_cast<const char*>(buffer.data()),
|
reinterpret_cast<const char*>(buffer.data()),
|
||||||
|
@ -241,11 +243,14 @@ auto FormController::prepareFinalData() const -> FinalData {
|
||||||
addValueToJSON(key, value);
|
addValueToJSON(key, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
auto hasErrors = false;
|
||||||
const auto scopes = ComputeScopes(this);
|
const auto scopes = ComputeScopes(this);
|
||||||
for (const auto &scope : scopes) {
|
for (const auto &scope : scopes) {
|
||||||
const auto ready = ComputeScopeRowReadyString(scope);
|
const auto ready = ComputeScopeRowReadyString(scope);
|
||||||
if (ready.isEmpty()) {
|
if (ready.isEmpty()) {
|
||||||
|
hasErrors = true;
|
||||||
_valueError.fire_copy(scope.fields);
|
_valueError.fire_copy(scope.fields);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
addValue(scope.fields);
|
addValue(scope.fields);
|
||||||
if (!scope.documents.empty()) {
|
if (!scope.documents.empty()) {
|
||||||
|
@ -257,6 +262,9 @@ auto FormController::prepareFinalData() const -> FinalData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (hasErrors) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
auto json = QJsonObject();
|
auto json = QJsonObject();
|
||||||
json.insert("secure_data", secureData);
|
json.insert("secure_data", secureData);
|
||||||
|
@ -274,6 +282,9 @@ void FormController::submit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto prepared = prepareFinalData();
|
const auto prepared = prepareFinalData();
|
||||||
|
if (prepared.hashes.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto credentialsEncryptedData = EncryptData(
|
const auto credentialsEncryptedData = EncryptData(
|
||||||
bytes::make_span(prepared.credentials));
|
bytes::make_span(prepared.credentials));
|
||||||
const auto credentialsEncryptedSecret = EncryptCredentialsSecret(
|
const auto credentialsEncryptedSecret = EncryptCredentialsSecret(
|
||||||
|
@ -433,6 +444,10 @@ QString FormController::passwordHint() const {
|
||||||
void FormController::uploadScan(
|
void FormController::uploadScan(
|
||||||
not_null<const Value*> value,
|
not_null<const Value*> value,
|
||||||
QByteArray &&content) {
|
QByteArray &&content) {
|
||||||
|
if (!canAddScan(value)) {
|
||||||
|
_view->showToast(lang(lng_passport_scans_limit_reached));
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto nonconst = findValue(value);
|
const auto nonconst = findValue(value);
|
||||||
auto scanIndex = int(nonconst->scansInEdit.size());
|
auto scanIndex = int(nonconst->scansInEdit.size());
|
||||||
nonconst->scansInEdit.emplace_back(
|
nonconst->scansInEdit.emplace_back(
|
||||||
|
@ -538,6 +553,12 @@ void FormController::scanDeleteRestore(
|
||||||
|
|
||||||
const auto nonconst = findValue(value);
|
const auto nonconst = findValue(value);
|
||||||
auto &scan = nonconst->scansInEdit[scanIndex];
|
auto &scan = nonconst->scansInEdit[scanIndex];
|
||||||
|
if (scan.deleted && !deleted) {
|
||||||
|
if (!canAddScan(value)) {
|
||||||
|
_view->showToast(lang(lng_passport_scans_limit_reached));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
scan.deleted = deleted;
|
scan.deleted = deleted;
|
||||||
_scanUpdated.fire(&scan);
|
_scanUpdated.fire(&scan);
|
||||||
}
|
}
|
||||||
|
@ -553,6 +574,13 @@ void FormController::selfieDeleteRestore(
|
||||||
_scanUpdated.fire(&scan);
|
_scanUpdated.fire(&scan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FormController::canAddScan(not_null<const Value*> value) const {
|
||||||
|
const auto scansCount = ranges::count_if(
|
||||||
|
value->scansInEdit,
|
||||||
|
[](const EditFile &scan) { return !scan.deleted; });
|
||||||
|
return (scansCount < kDocumentScansLimit);
|
||||||
|
}
|
||||||
|
|
||||||
void FormController::subscribeToUploader() {
|
void FormController::subscribeToUploader() {
|
||||||
if (_uploaderSubscriptions) {
|
if (_uploaderSubscriptions) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -212,6 +212,7 @@ public:
|
||||||
rpl::producer<QString> passwordError() const;
|
rpl::producer<QString> passwordError() const;
|
||||||
QString passwordHint() const;
|
QString passwordHint() const;
|
||||||
|
|
||||||
|
bool canAddScan(not_null<const Value*> value) const;
|
||||||
void uploadScan(not_null<const Value*> value, QByteArray &&content);
|
void uploadScan(not_null<const Value*> value, QByteArray &&content);
|
||||||
void deleteScan(not_null<const Value*> value, int fileIndex);
|
void deleteScan(not_null<const Value*> value, int fileIndex);
|
||||||
void restoreScan(not_null<const Value*> value, int fileIndex);
|
void restoreScan(not_null<const Value*> value, int fileIndex);
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
virtual void editScope(int index) = 0;
|
virtual void editScope(int index) = 0;
|
||||||
|
|
||||||
virtual void showBox(object_ptr<BoxContent> box) = 0;
|
virtual void showBox(object_ptr<BoxContent> box) = 0;
|
||||||
|
virtual void showToast(const QString &text) = 0;
|
||||||
|
|
||||||
virtual ~ViewController() {
|
virtual ~ViewController() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "passport/passport_panel_edit_scans.h"
|
#include "passport/passport_panel_edit_scans.h"
|
||||||
#include "passport/passport_panel.h"
|
#include "passport/passport_panel.h"
|
||||||
#include "boxes/confirm_box.h"
|
#include "boxes/confirm_box.h"
|
||||||
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/countryinput.h"
|
#include "ui/countryinput.h"
|
||||||
#include "layout.h"
|
#include "layout.h"
|
||||||
|
|
||||||
|
@ -363,6 +364,14 @@ QString PanelController::defaultPhoneNumber() const {
|
||||||
return _form->defaultPhoneNumber();
|
return _form->defaultPhoneNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PanelController::canAddScan() const {
|
||||||
|
Expects(_editScope != nullptr);
|
||||||
|
Expects(_editDocumentIndex >= 0
|
||||||
|
&& _editDocumentIndex < _editScope->documents.size());
|
||||||
|
|
||||||
|
return _form->canAddScan(_editScope->documents[_editDocumentIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
void PanelController::uploadScan(QByteArray &&content) {
|
void PanelController::uploadScan(QByteArray &&content) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editDocumentIndex >= 0
|
Expects(_editDocumentIndex >= 0
|
||||||
|
@ -858,6 +867,14 @@ void PanelController::showBox(object_ptr<BoxContent> box) {
|
||||||
_panel->showBox(std::move(box));
|
_panel->showBox(std::move(box));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PanelController::showToast(const QString &text) {
|
||||||
|
Expects(_panel != nullptr);
|
||||||
|
|
||||||
|
auto toast = Ui::Toast::Config();
|
||||||
|
toast.text = text;
|
||||||
|
Ui::Toast::Show(_panel.get(), toast);
|
||||||
|
}
|
||||||
|
|
||||||
rpl::lifetime &PanelController::lifetime() {
|
rpl::lifetime &PanelController::lifetime() {
|
||||||
return _lifetime;
|
return _lifetime;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
rpl::producer<QString> passwordError() const;
|
rpl::producer<QString> passwordError() const;
|
||||||
QString passwordHint() const;
|
QString passwordHint() const;
|
||||||
|
|
||||||
|
bool canAddScan() const;
|
||||||
void uploadScan(QByteArray &&content);
|
void uploadScan(QByteArray &&content);
|
||||||
void deleteScan(int fileIndex);
|
void deleteScan(int fileIndex);
|
||||||
void restoreScan(int fileIndex);
|
void restoreScan(int fileIndex);
|
||||||
|
@ -89,6 +90,7 @@ public:
|
||||||
void cancelEditScope();
|
void cancelEditScope();
|
||||||
|
|
||||||
void showBox(object_ptr<BoxContent> box) override;
|
void showBox(object_ptr<BoxContent> box) override;
|
||||||
|
void showToast(const QString &text) override;
|
||||||
|
|
||||||
void cancelAuth();
|
void cancelAuth();
|
||||||
|
|
||||||
|
|
|
@ -300,6 +300,13 @@ PanelEditDocument::Result PanelEditDocument::collect() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PanelEditDocument::validate() {
|
bool PanelEditDocument::validate() {
|
||||||
|
if (const auto error = _editScans->validateGetErrorTop()) {
|
||||||
|
const auto errortop = _editScans->mapToGlobal(QPoint(0, *error));
|
||||||
|
const auto scrolltop = _scroll->mapToGlobal(QPoint(0, 0));
|
||||||
|
const auto scrolldelta = errortop.y() - scrolltop.y();
|
||||||
|
_scroll->scrollToY(_scroll->scrollTop() + scrolldelta);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
auto first = QPointer<PanelDetailsRow>();
|
auto first = QPointer<PanelDetailsRow>();
|
||||||
for (const auto [i, field] : base::reversed(_details)) {
|
for (const auto [i, field] : base::reversed(_details)) {
|
||||||
const auto &row = _scheme.rows[i];
|
const auto &row = _scheme.rows[i];
|
||||||
|
|
|
@ -196,6 +196,22 @@ EditScans::EditScans(
|
||||||
setupContent(header);
|
setupContent(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base::optional<int> EditScans::validateGetErrorTop() {
|
||||||
|
const auto exists = ranges::find(
|
||||||
|
_files,
|
||||||
|
false,
|
||||||
|
[](const ScanInfo &file) { return file.deleted; }) != end(_files);
|
||||||
|
if (!exists) {
|
||||||
|
toggleError(true);
|
||||||
|
return (_files.size() > 5) ? _upload->y() : _header->y();
|
||||||
|
}
|
||||||
|
if (_selfie && (!_selfie->key.id || _selfie->deleted)) {
|
||||||
|
toggleSelfieError(true);
|
||||||
|
return _selfieHeader->y();
|
||||||
|
}
|
||||||
|
return base::none;
|
||||||
|
}
|
||||||
|
|
||||||
void EditScans::setupContent(const QString &header) {
|
void EditScans::setupContent(const QString &header) {
|
||||||
const auto inner = _content.data();
|
const auto inner = _content.data();
|
||||||
inner->move(0, 0);
|
inner->move(0, 0);
|
||||||
|
@ -307,6 +323,9 @@ void EditScans::updateScan(ScanInfo &&info) {
|
||||||
Assert(_selfie != nullptr);
|
Assert(_selfie != nullptr);
|
||||||
if (_selfie->key.id) {
|
if (_selfie->key.id) {
|
||||||
updateRow(_selfieRow->entity(), info);
|
updateRow(_selfieRow->entity(), info);
|
||||||
|
if (!info.deleted) {
|
||||||
|
hideSelfieError();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
createSelfieRow(info);
|
createSelfieRow(info);
|
||||||
_selfieWrap->resizeToWidth(width());
|
_selfieWrap->resizeToWidth(width());
|
||||||
|
@ -325,6 +344,9 @@ void EditScans::updateScan(ScanInfo &&info) {
|
||||||
scan->setStatus(i->status);
|
scan->setStatus(i->status);
|
||||||
scan->setImage(i->thumb);
|
scan->setImage(i->thumb);
|
||||||
scan->setDeleted(i->deleted);
|
scan->setDeleted(i->deleted);
|
||||||
|
if (!i->deleted) {
|
||||||
|
hideError();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_files.push_back(std::move(info));
|
_files.push_back(std::move(info));
|
||||||
pushScan(_files.back());
|
pushScan(_files.back());
|
||||||
|
@ -352,6 +374,8 @@ void EditScans::createSelfieRow(const ScanInfo &info) {
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
_controller->restoreSelfie();
|
_controller->restoreSelfie();
|
||||||
}, row->lifetime());
|
}, row->lifetime());
|
||||||
|
|
||||||
|
hideSelfieError();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditScans::pushScan(const ScanInfo &info) {
|
void EditScans::pushScan(const ScanInfo &info) {
|
||||||
|
@ -373,6 +397,8 @@ void EditScans::pushScan(const ScanInfo &info) {
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
_controller->restoreScan(index);
|
_controller->restoreScan(index);
|
||||||
}, scan->lifetime());
|
}, scan->lifetime());
|
||||||
|
|
||||||
|
hideError();
|
||||||
}
|
}
|
||||||
|
|
||||||
base::unique_qptr<Ui::SlideWrap<ScanButton>> EditScans::createScan(
|
base::unique_qptr<Ui::SlideWrap<ScanButton>> EditScans::createScan(
|
||||||
|
@ -393,6 +419,10 @@ base::unique_qptr<Ui::SlideWrap<ScanButton>> EditScans::createScan(
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditScans::chooseScan() {
|
void EditScans::chooseScan() {
|
||||||
|
if (!_controller->canAddScan()) {
|
||||||
|
_controller->showToast(lang(lng_passport_scans_limit_reached));
|
||||||
|
return;
|
||||||
|
}
|
||||||
ChooseScan(base::lambda_guarded(this, [=](QByteArray &&content) {
|
ChooseScan(base::lambda_guarded(this, [=](QByteArray &&content) {
|
||||||
_controller->uploadScan(std::move(content));
|
_controller->uploadScan(std::move(content));
|
||||||
}));
|
}));
|
||||||
|
@ -437,4 +467,59 @@ rpl::producer<QString> EditScans::uploadButtonText() const {
|
||||||
: lng_passport_upload_more) | Info::Profile::ToUpperValue();
|
: lng_passport_upload_more) | Info::Profile::ToUpperValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditScans::hideError() {
|
||||||
|
toggleError(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditScans::toggleError(bool shown) {
|
||||||
|
if (_errorShown != shown) {
|
||||||
|
_errorShown = shown;
|
||||||
|
_errorAnimation.start(
|
||||||
|
[=] { errorAnimationCallback(); },
|
||||||
|
_errorShown ? 0. : 1.,
|
||||||
|
_errorShown ? 1. : 0.,
|
||||||
|
st::passportDetailsField.duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditScans::errorAnimationCallback() {
|
||||||
|
const auto error = _errorAnimation.current(_errorShown ? 1. : 0.);
|
||||||
|
if (error == 0.) {
|
||||||
|
_upload->setColorOverride(base::none);
|
||||||
|
} else {
|
||||||
|
_upload->setColorOverride(anim::color(
|
||||||
|
st::passportUploadButton.textFg,
|
||||||
|
st::boxTextFgError,
|
||||||
|
error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditScans::hideSelfieError() {
|
||||||
|
toggleSelfieError(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditScans::toggleSelfieError(bool shown) {
|
||||||
|
if (_selfieErrorShown != shown) {
|
||||||
|
_selfieErrorShown = shown;
|
||||||
|
_selfieErrorAnimation.start(
|
||||||
|
[=] { selfieErrorAnimationCallback(); },
|
||||||
|
_selfieErrorShown ? 0. : 1.,
|
||||||
|
_selfieErrorShown ? 1. : 0.,
|
||||||
|
st::passportDetailsField.duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditScans::selfieErrorAnimationCallback() {
|
||||||
|
const auto error = _selfieErrorAnimation.current(
|
||||||
|
_selfieErrorShown ? 1. : 0.);
|
||||||
|
if (error == 0.) {
|
||||||
|
_selfieUpload->setColorOverride(base::none);
|
||||||
|
} else {
|
||||||
|
_selfieUpload->setColorOverride(anim::color(
|
||||||
|
st::passportUploadButton.textFg,
|
||||||
|
st::boxTextFgError,
|
||||||
|
error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Passport
|
} // namespace Passport
|
||||||
|
|
|
@ -39,6 +39,8 @@ public:
|
||||||
std::vector<ScanInfo> &&files,
|
std::vector<ScanInfo> &&files,
|
||||||
std::unique_ptr<ScanInfo> &&selfie);
|
std::unique_ptr<ScanInfo> &&selfie);
|
||||||
|
|
||||||
|
base::optional<int> validateGetErrorTop();
|
||||||
|
|
||||||
static void ChooseScan(base::lambda<void(QByteArray&&)> callback);
|
static void ChooseScan(base::lambda<void(QByteArray&&)> callback);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -55,6 +57,14 @@ private:
|
||||||
|
|
||||||
rpl::producer<QString> uploadButtonText() const;
|
rpl::producer<QString> uploadButtonText() const;
|
||||||
|
|
||||||
|
void toggleError(bool shown);
|
||||||
|
void hideError();
|
||||||
|
void errorAnimationCallback();
|
||||||
|
|
||||||
|
void toggleSelfieError(bool shown);
|
||||||
|
void hideSelfieError();
|
||||||
|
void selfieErrorAnimationCallback();
|
||||||
|
|
||||||
not_null<PanelController*> _controller;
|
not_null<PanelController*> _controller;
|
||||||
std::vector<ScanInfo> _files;
|
std::vector<ScanInfo> _files;
|
||||||
std::unique_ptr<ScanInfo> _selfie;
|
std::unique_ptr<ScanInfo> _selfie;
|
||||||
|
@ -66,11 +76,15 @@ private:
|
||||||
std::vector<base::unique_qptr<Ui::SlideWrap<ScanButton>>> _rows;
|
std::vector<base::unique_qptr<Ui::SlideWrap<ScanButton>>> _rows;
|
||||||
QPointer<Info::Profile::Button> _upload;
|
QPointer<Info::Profile::Button> _upload;
|
||||||
rpl::event_stream<rpl::producer<QString>> _uploadTexts;
|
rpl::event_stream<rpl::producer<QString>> _uploadTexts;
|
||||||
|
bool _errorShown = false;
|
||||||
|
Animation _errorAnimation;
|
||||||
|
|
||||||
QPointer<Ui::SlideWrap<Ui::FlatLabel>> _selfieHeader;
|
QPointer<Ui::SlideWrap<Ui::FlatLabel>> _selfieHeader;
|
||||||
QPointer<Ui::VerticalLayout> _selfieWrap;
|
QPointer<Ui::VerticalLayout> _selfieWrap;
|
||||||
base::unique_qptr<Ui::SlideWrap<ScanButton>> _selfieRow;
|
base::unique_qptr<Ui::SlideWrap<ScanButton>> _selfieRow;
|
||||||
QPointer<Info::Profile::Button> _selfieUpload;
|
QPointer<Info::Profile::Button> _selfieUpload;
|
||||||
|
bool _selfieErrorShown = false;
|
||||||
|
Animation _selfieErrorAnimation;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue