diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_identity.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_identity.cpp index dd07fccee..907fcba04 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_identity.cpp +++ b/Telegram/SourceFiles/passport/passport_panel_edit_identity.cpp @@ -9,184 +9,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "passport/passport_panel_controller.h" #include "passport/passport_panel_details_row.h" +#include "passport/passport_panel_edit_scans.h" #include "ui/widgets/input_fields.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/labels.h" #include "ui/widgets/buttons.h" #include "ui/widgets/shadow.h" #include "ui/wrap/vertical_layout.h" -#include "ui/wrap/slide_wrap.h" #include "ui/wrap/fade_wrap.h" -#include "ui/text_options.h" -#include "info/profile/info_profile_button.h" -#include "info/profile/info_profile_values.h" #include "boxes/abstract_box.h" #include "lang/lang_keys.h" -#include "core/file_utilities.h" #include "styles/style_widgets.h" #include "styles/style_boxes.h" #include "styles/style_passport.h" namespace Passport { -class ScanButton : public Ui::AbstractButton { -public: - ScanButton( - QWidget *parent, - const style::PassportScanRow &st, - const QString &name, - const QString &status, - bool deleted); - - void setImage(const QImage &image); - void setStatus(const QString &status); - void setDeleted(bool deleted); - - rpl::producer<> deleteClicks() const { - return _delete->entity()->clicks(); - } - rpl::producer<> restoreClicks() const { - return _restore->entity()->clicks(); - } - -protected: - int resizeGetHeight(int newWidth) override; - - void paintEvent(QPaintEvent *e) override; - -private: - int countAvailableWidth() const; - - const style::PassportScanRow &_st; - Text _name; - Text _status; - int _nameHeight = 0; - int _statusHeight = 0; - QImage _image; - object_ptr> _delete; - object_ptr> _restore; - -}; - -ScanButton::ScanButton( - QWidget *parent, - const style::PassportScanRow &st, - const QString &name, - const QString &status, - bool deleted) -: AbstractButton(parent) -, _st(st) -, _name( - st::passportScanNameStyle, - name, - Ui::NameTextOptions()) -, _status( - st::defaultTextStyle, - status, - Ui::NameTextOptions()) -, _delete(this, object_ptr(this, _st.remove)) -, _restore( - this, - object_ptr( - this, - langFactory(lng_passport_delete_scan_undo), - _st.restore)) { - _delete->toggle(!deleted, anim::type::instant); - _restore->toggle(deleted, anim::type::instant); -} - -void ScanButton::setImage(const QImage &image) { - _image = image; - update(); -} - -void ScanButton::setStatus(const QString &status) { - _status.setText( - st::defaultTextStyle, - status, - Ui::NameTextOptions()); - update(); -} - -void ScanButton::setDeleted(bool deleted) { - _delete->toggle(!deleted, anim::type::instant); - _restore->toggle(deleted, anim::type::instant); - update(); -} - -int ScanButton::resizeGetHeight(int newWidth) { - _nameHeight = st::semiboldFont->height; - _statusHeight = st::normalFont->height; - const auto result = _st.padding.top() + _st.size + _st.padding.bottom(); - const auto right = _st.padding.right(); - _delete->moveToRight( - right, - (result - _delete->height()) / 2, - newWidth); - _restore->moveToRight( - right, - (result - _restore->height()) / 2, - newWidth); - return result + st::lineWidth; -} - -int ScanButton::countAvailableWidth() const { - return width() - - _st.padding.left() - - _st.textLeft - - _st.padding.right() - - std::max(_delete->width(), _restore->width()); -} - -void ScanButton::paintEvent(QPaintEvent *e) { - Painter p(this); - - const auto left = _st.padding.left(); - const auto top = _st.padding.top(); - p.fillRect( - left, - height() - _st.border, - width() - left, - _st.border, - _st.borderFg); - - if (_restore->toggled()) { - p.setOpacity(st::passportScanDeletedOpacity); - } - - if (_image.isNull()) { - p.fillRect(left, top, _st.size, _st.size, Qt::black); - } else { - PainterHighQualityEnabler hq(p); - const auto fromRect = [&] { - if (_image.width() > _image.height()) { - const auto shift = (_image.width() - _image.height()) / 2; - return QRect(shift, 0, _image.height(), _image.height()); - } else { - const auto shift = (_image.height() - _image.width()) / 2; - return QRect(0, shift, _image.width(), _image.width()); - } - }(); - p.drawImage(QRect(left, top, _st.size, _st.size), _image, fromRect); - } - const auto availableWidth = countAvailableWidth(); - - p.setPen(st::windowFg); - _name.drawLeftElided( - p, - left + _st.textLeft, - top + _st.nameTop, - availableWidth, - width()); - p.setPen(st::windowSubTextFg); - _status.drawLeftElided( - p, - left + _st.textLeft, - top + _st.statusTop, - availableWidth, - width()); -} - PanelEditIdentity::PanelEditIdentity( QWidget*, not_null controller, @@ -194,7 +32,6 @@ PanelEditIdentity::PanelEditIdentity( const ValueMap &scanData, std::vector &&files) : _controller(controller) -, _files(std::move(files)) , _scroll(this, st::passportPanelScroll) , _topShadow(this) , _bottomShadow(this) @@ -202,13 +39,14 @@ PanelEditIdentity::PanelEditIdentity( this, langFactory(lng_passport_save_value), st::passportPanelSaveValue) { - setupControls(data, scanData); + setupControls(data, scanData, std::move(files)); } void PanelEditIdentity::setupControls( const ValueMap &data, - const ValueMap &scanData) { - const auto inner = setupContent(data, scanData); + const ValueMap &scanData, + std::vector &&files) { + const auto inner = setupContent(data, scanData, std::move(files)); using namespace rpl::mappers; @@ -219,15 +57,12 @@ void PanelEditIdentity::setupControls( save(); }); }); - _controller->scanUpdated( - ) | rpl::start_with_next([=](ScanInfo &&info) { - updateScan(std::move(info)); - }, lifetime()); } not_null PanelEditIdentity::setupContent( const ValueMap &data, - const ValueMap &scanData) { + const ValueMap &scanData, + std::vector &&files) { const auto inner = _scroll->setOwnedWidget( object_ptr(this)); _scroll->widthValue( @@ -235,42 +70,8 @@ not_null PanelEditIdentity::setupContent( inner->resizeToWidth(width); }, inner->lifetime()); - _scansDivider = inner->add( - object_ptr>( - inner, - object_ptr( - inner, - st::passportFormDividerHeight))); - _scansDivider->toggle(_files.empty(), anim::type::instant); - - _scansHeader = inner->add( - object_ptr>( - inner, - object_ptr( - inner, - lang(lng_passport_upload_header), - Ui::FlatLabel::InitType::Simple, - st::passportFormHeader), - st::passportUploadHeaderPadding)); - _scansHeader->toggle(!_files.empty(), anim::type::instant); - - _scansWrap = inner->add(object_ptr(inner)); - for (const auto &scan : _files) { - pushScan(scan); - _scans.back()->show(anim::type::instant); - } - - _scansUpload = inner->add( - object_ptr( - inner, - _scansUploadTexts.events_starting_with( - uploadButtonText() - ) | rpl::flatten_latest(), - st::passportUploadButton), - st::passportUploadButtonPadding); - _scansUpload->addClickHandler([=] { - chooseScan(); - }); + _editScans = inner->add( + object_ptr(inner, _controller, std::move(files))); inner->add(object_ptr( inner, @@ -302,53 +103,6 @@ not_null PanelEditIdentity::setupContent( return inner; } -void PanelEditIdentity::updateScan(ScanInfo &&info) { - const auto i = ranges::find(_files, info.key, [](const ScanInfo &file) { - return file.key; - }); - if (i != _files.end()) { - *i = info; - const auto scan = _scans[i - _files.begin()]->entity(); - scan->setStatus(i->status); - scan->setImage(i->thumb); - scan->setDeleted(i->deleted); - } else { - _files.push_back(std::move(info)); - pushScan(_files.back()); - _scansWrap->resizeToWidth(width()); - _scans.back()->show(anim::type::normal); - _scansDivider->hide(anim::type::normal); - _scansHeader->show(anim::type::normal); - _scansUploadTexts.fire(uploadButtonText()); - } -} - -void PanelEditIdentity::pushScan(const ScanInfo &info) { - const auto index = _scans.size(); - _scans.push_back(base::unique_qptr>( - _scansWrap->add(object_ptr>( - _scansWrap, - object_ptr( - _scansWrap, - st::passportScanRow, - lng_passport_scan_index(lt_index, QString::number(index + 1)), - info.status, - info.deleted))))); - _scans.back()->hide(anim::type::instant); - const auto scan = _scans.back()->entity(); - scan->setImage(info.thumb); - - scan->deleteClicks( - ) | rpl::start_with_next([=] { - _controller->deleteScan(index); - }, scan->lifetime()); - - scan->restoreClicks( - ) | rpl::start_with_next([=] { - _controller->restoreScan(index); - }, scan->lifetime()); -} - void PanelEditIdentity::focusInEvent(QFocusEvent *e) { _firstName->setFocusFast(); } @@ -370,38 +124,6 @@ void PanelEditIdentity::updateControlsGeometry() { _scroll->updateBars(); } -void PanelEditIdentity::chooseScan() { - const auto filter = FileDialog::AllFilesFilter() - + qsl(";;Image files (*") - + cImgExtensions().join(qsl(" *")) - + qsl(")"); - const auto callback = [=](FileDialog::OpenResult &&result) { - if (result.paths.size() == 1) { - encryptScan(result.paths.front()); - } else if (!result.remoteContent.isEmpty()) { - encryptScanContent(std::move(result.remoteContent)); - } - }; - FileDialog::GetOpenPath( - lang(lng_passport_choose_image), - filter, - base::lambda_guarded(this, callback)); -} - -void PanelEditIdentity::encryptScan(const QString &path) { - encryptScanContent([&] { - QFile f(path); - if (!f.open(QIODevice::ReadOnly)) { - return QByteArray(); - } - return f.readAll(); - }()); -} - -void PanelEditIdentity::encryptScanContent(QByteArray &&content) { - _controller->uploadScan(std::move(content)); -} - void PanelEditIdentity::save() { auto data = ValueMap(); data.fields["first_name"] = _firstName->getLastText(); @@ -410,10 +132,4 @@ void PanelEditIdentity::save() { _controller->saveScope(std::move(data), std::move(scanData)); } -rpl::producer PanelEditIdentity::uploadButtonText() const { - return Lang::Viewer(_files.empty() - ? lng_passport_upload_scans - : lng_passport_upload_more) | Info::Profile::ToUpperValue(); -} - } // namespace Passport diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_identity.h b/Telegram/SourceFiles/passport/passport_panel_edit_identity.h index 47840bfb4..5a1f0f77f 100644 --- a/Telegram/SourceFiles/passport/passport_panel_edit_identity.h +++ b/Telegram/SourceFiles/passport/passport_panel_edit_identity.h @@ -9,32 +9,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/rp_widget.h" -class BoxContentDivider; - namespace Ui { class InputField; -class VerticalLayout; class ScrollArea; class FadeShadow; class PlainShadow; -class FlatLabel; class RoundButton; -template -class SlideWrap; } // namespace Ui -namespace Info { -namespace Profile { -class Button; -} // namespace Profile -} // namespace Info - namespace Passport { class PanelController; struct ValueMap; struct ScanInfo; -class ScanButton; +class EditScans; class PanelEditIdentity : public Ui::RpWidget { public: @@ -50,35 +38,25 @@ protected: void resizeEvent(QResizeEvent *e) override; private: - void setupControls(const ValueMap &data, const ValueMap &scanData); + void setupControls( + const ValueMap &data, + const ValueMap &scanData, + std::vector &&files); not_null setupContent( const ValueMap &data, - const ValueMap &scanData); + const ValueMap &scanData, + std::vector &&files); void updateControlsGeometry(); - void chooseScan(); - void encryptScan(const QString &path); - void encryptScanContent(QByteArray &&content); - void updateScan(ScanInfo &&info); - void pushScan(const ScanInfo &info); - - rpl::producer uploadButtonText() const; void save(); not_null _controller; - std::vector _files; object_ptr _scroll; object_ptr _topShadow; object_ptr _bottomShadow; - QPointer> _scansDivider; - QPointer> _scansHeader; - QPointer _scansWrap; - std::vector>> _scans; - QPointer _scansUpload; - rpl::event_stream> _scansUploadTexts; - + QPointer _editScans; QPointer _firstName; QPointer _lastName; diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp b/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp new file mode 100644 index 000000000..8082ee77a --- /dev/null +++ b/Telegram/SourceFiles/passport/passport_panel_edit_scans.cpp @@ -0,0 +1,336 @@ +/* +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 "passport/passport_panel_edit_scans.h" + +#include "passport/passport_panel_controller.h" +#include "info/profile/info_profile_button.h" +#include "info/profile/info_profile_values.h" +#include "ui/widgets/buttons.h" +#include "ui/widgets/labels.h" +#include "ui/wrap/fade_wrap.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/wrap/vertical_layout.h" +#include "ui/text_options.h" +#include "core/file_utilities.h" +#include "lang/lang_keys.h" +#include "boxes/abstract_box.h" +#include "styles/style_passport.h" + +namespace Passport { + +class ScanButton : public Ui::AbstractButton { +public: + ScanButton( + QWidget *parent, + const style::PassportScanRow &st, + const QString &name, + const QString &status, + bool deleted); + + void setImage(const QImage &image); + void setStatus(const QString &status); + void setDeleted(bool deleted); + + rpl::producer<> deleteClicks() const { + return _delete->entity()->clicks(); + } + rpl::producer<> restoreClicks() const { + return _restore->entity()->clicks(); + } + +protected: + int resizeGetHeight(int newWidth) override; + + void paintEvent(QPaintEvent *e) override; + +private: + int countAvailableWidth() const; + + const style::PassportScanRow &_st; + Text _name; + Text _status; + int _nameHeight = 0; + int _statusHeight = 0; + QImage _image; + object_ptr> _delete; + object_ptr> _restore; + +}; + +ScanButton::ScanButton( + QWidget *parent, + const style::PassportScanRow &st, + const QString &name, + const QString &status, + bool deleted) +: AbstractButton(parent) +, _st(st) +, _name( + st::passportScanNameStyle, + name, + Ui::NameTextOptions()) +, _status( + st::defaultTextStyle, + status, + Ui::NameTextOptions()) +, _delete(this, object_ptr(this, _st.remove)) +, _restore( + this, + object_ptr( + this, + langFactory(lng_passport_delete_scan_undo), + _st.restore)) { + _delete->toggle(!deleted, anim::type::instant); + _restore->toggle(deleted, anim::type::instant); +} + +void ScanButton::setImage(const QImage &image) { + _image = image; + update(); +} + +void ScanButton::setStatus(const QString &status) { + _status.setText( + st::defaultTextStyle, + status, + Ui::NameTextOptions()); + update(); +} + +void ScanButton::setDeleted(bool deleted) { + _delete->toggle(!deleted, anim::type::instant); + _restore->toggle(deleted, anim::type::instant); + update(); +} + +int ScanButton::resizeGetHeight(int newWidth) { + _nameHeight = st::semiboldFont->height; + _statusHeight = st::normalFont->height; + const auto result = _st.padding.top() + _st.size + _st.padding.bottom(); + const auto right = _st.padding.right(); + _delete->moveToRight( + right, + (result - _delete->height()) / 2, + newWidth); + _restore->moveToRight( + right, + (result - _restore->height()) / 2, + newWidth); + return result + st::lineWidth; +} + +int ScanButton::countAvailableWidth() const { + return width() + - _st.padding.left() + - _st.textLeft + - _st.padding.right() + - std::max(_delete->width(), _restore->width()); +} + +void ScanButton::paintEvent(QPaintEvent *e) { + Painter p(this); + + const auto left = _st.padding.left(); + const auto top = _st.padding.top(); + p.fillRect( + left, + height() - _st.border, + width() - left, + _st.border, + _st.borderFg); + + if (_restore->toggled()) { + p.setOpacity(st::passportScanDeletedOpacity); + } + + if (_image.isNull()) { + p.fillRect(left, top, _st.size, _st.size, Qt::black); + } else { + PainterHighQualityEnabler hq(p); + const auto fromRect = [&] { + if (_image.width() > _image.height()) { + const auto shift = (_image.width() - _image.height()) / 2; + return QRect(shift, 0, _image.height(), _image.height()); + } else { + const auto shift = (_image.height() - _image.width()) / 2; + return QRect(0, shift, _image.width(), _image.width()); + } + }(); + p.drawImage(QRect(left, top, _st.size, _st.size), _image, fromRect); + } + const auto availableWidth = countAvailableWidth(); + + p.setPen(st::windowFg); + _name.drawLeftElided( + p, + left + _st.textLeft, + top + _st.nameTop, + availableWidth, + width()); + p.setPen(st::windowSubTextFg); + _status.drawLeftElided( + p, + left + _st.textLeft, + top + _st.statusTop, + availableWidth, + width()); +} + +EditScans::EditScans( + QWidget *parent, + not_null controller, + std::vector &&files) +: RpWidget(parent) +, _controller(controller) +, _files(std::move(files)) +, _content(this) { + setupContent(); +} + +void EditScans::setupContent() { + const auto inner = _content.data(); + inner->move(0, 0); + + _divider = inner->add( + object_ptr>( + inner, + object_ptr( + inner, + st::passportFormDividerHeight))); + _divider->toggle(_files.empty(), anim::type::instant); + + _header = inner->add( + object_ptr>( + inner, + object_ptr( + inner, + lang(lng_passport_upload_header), + Ui::FlatLabel::InitType::Simple, + st::passportFormHeader), + st::passportUploadHeaderPadding)); + _header->toggle(!_files.empty(), anim::type::instant); + + _wrap = inner->add(object_ptr(inner)); + for (const auto &scan : _files) { + pushScan(scan); + _rows.back()->show(anim::type::instant); + } + + _upload = inner->add( + object_ptr( + inner, + _uploadTexts.events_starting_with( + uploadButtonText() + ) | rpl::flatten_latest(), + st::passportUploadButton), + st::passportUploadButtonPadding); + _upload->addClickHandler([=] { + chooseScan(); + }); + _controller->scanUpdated( + ) | rpl::start_with_next([=](ScanInfo &&info) { + updateScan(std::move(info)); + }, lifetime()); + + widthValue( + ) | rpl::start_with_next([=](int width) { + _content->resizeToWidth(width); + }, _content->lifetime()); + + _content->heightValue( + ) | rpl::start_with_next([=](int height) { + resize(width(), height); + }, _content->lifetime()); +} + +void EditScans::updateScan(ScanInfo &&info) { + const auto i = ranges::find(_files, info.key, [](const ScanInfo &file) { + return file.key; + }); + if (i != _files.end()) { + *i = info; + const auto scan = _rows[i - _files.begin()]->entity(); + scan->setStatus(i->status); + scan->setImage(i->thumb); + scan->setDeleted(i->deleted); + } else { + _files.push_back(std::move(info)); + pushScan(_files.back()); + _wrap->resizeToWidth(width()); + _rows.back()->show(anim::type::normal); + _divider->hide(anim::type::normal); + _header->show(anim::type::normal); + _uploadTexts.fire(uploadButtonText()); + } +} + +void EditScans::pushScan(const ScanInfo &info) { + const auto index = _rows.size(); + _rows.push_back(base::unique_qptr>( + _wrap->add(object_ptr>( + _wrap, + object_ptr( + _wrap, + st::passportScanRow, + lng_passport_scan_index(lt_index, QString::number(index + 1)), + info.status, + info.deleted))))); + _rows.back()->hide(anim::type::instant); + const auto scan = _rows.back()->entity(); + scan->setImage(info.thumb); + + scan->deleteClicks( + ) | rpl::start_with_next([=] { + _controller->deleteScan(index); + }, scan->lifetime()); + + scan->restoreClicks( + ) | rpl::start_with_next([=] { + _controller->restoreScan(index); + }, scan->lifetime()); +} + +void EditScans::chooseScan() { + const auto filter = FileDialog::AllFilesFilter() + + qsl(";;Image files (*") + + cImgExtensions().join(qsl(" *")) + + qsl(")"); + const auto callback = [=](FileDialog::OpenResult &&result) { + if (result.paths.size() == 1) { + encryptScan(result.paths.front()); + } else if (!result.remoteContent.isEmpty()) { + encryptScanContent(std::move(result.remoteContent)); + } + }; + FileDialog::GetOpenPath( + lang(lng_passport_choose_image), + filter, + base::lambda_guarded(this, callback)); +} + +void EditScans::encryptScan(const QString &path) { + encryptScanContent([&] { + QFile f(path); + if (!f.open(QIODevice::ReadOnly)) { + return QByteArray(); + } + return f.readAll(); + }()); +} + +void EditScans::encryptScanContent(QByteArray &&content) { + _controller->uploadScan(std::move(content)); +} + +rpl::producer EditScans::uploadButtonText() const { + return Lang::Viewer(_files.empty() + ? lng_passport_upload_scans + : lng_passport_upload_more) | Info::Profile::ToUpperValue(); +} + +} // namespace Passport diff --git a/Telegram/SourceFiles/passport/passport_panel_edit_scans.h b/Telegram/SourceFiles/passport/passport_panel_edit_scans.h new file mode 100644 index 000000000..074610b1d --- /dev/null +++ b/Telegram/SourceFiles/passport/passport_panel_edit_scans.h @@ -0,0 +1,63 @@ +/* +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 "ui/rp_widget.h" + +class BoxContentDivider; + +namespace Ui { +class VerticalLayout; +class FlatLabel; +template +class SlideWrap; +} // namespace Ui + +namespace Info { +namespace Profile { +class Button; +} // namespace Profile +} // namespace Info + +namespace Passport { + +class PanelController; +class ScanButton; +struct ScanInfo; + +class EditScans : public Ui::RpWidget { +public: + EditScans( + QWidget *parent, + not_null controller, + std::vector &&files); + +private: + void setupContent(); + void chooseScan(); + void encryptScan(const QString &path); + void encryptScanContent(QByteArray &&content); + void updateScan(ScanInfo &&info); + void pushScan(const ScanInfo &info); + + rpl::producer uploadButtonText() const; + + not_null _controller; + std::vector _files; + + object_ptr _content; + QPointer> _divider; + QPointer> _header; + QPointer _wrap; + std::vector>> _rows; + QPointer _upload; + rpl::event_stream> _uploadTexts; + +}; + +} // namespace Passport diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index f47b2ebe0..ef19383fa 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -468,6 +468,8 @@ <(src_loc)/passport/passport_panel_details_row.h <(src_loc)/passport/passport_panel_edit_identity.cpp <(src_loc)/passport/passport_panel_edit_identity.h +<(src_loc)/passport/passport_panel_edit_scans.cpp +<(src_loc)/passport/passport_panel_edit_scans.h <(src_loc)/passport/passport_panel_form.cpp <(src_loc)/passport/passport_panel_form.h <(src_loc)/passport/passport_panel_password.cpp