mirror of https://github.com/procxx/kepka.git
Move scans upload to a separate module.
This commit is contained in:
parent
f0b7ff24b1
commit
2790919733
|
@ -9,184 +9,22 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "passport/passport_panel_controller.h"
|
#include "passport/passport_panel_controller.h"
|
||||||
#include "passport/passport_panel_details_row.h"
|
#include "passport/passport_panel_details_row.h"
|
||||||
|
#include "passport/passport_panel_edit_scans.h"
|
||||||
#include "ui/widgets/input_fields.h"
|
#include "ui/widgets/input_fields.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "ui/widgets/labels.h"
|
#include "ui/widgets/labels.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/wrap/vertical_layout.h"
|
#include "ui/wrap/vertical_layout.h"
|
||||||
#include "ui/wrap/slide_wrap.h"
|
|
||||||
#include "ui/wrap/fade_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 "boxes/abstract_box.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "core/file_utilities.h"
|
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
#include "styles/style_passport.h"
|
#include "styles/style_passport.h"
|
||||||
|
|
||||||
namespace Passport {
|
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<Ui::FadeWrapScaled<Ui::IconButton>> _delete;
|
|
||||||
object_ptr<Ui::FadeWrapScaled<Ui::RoundButton>> _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<Ui::IconButton>(this, _st.remove))
|
|
||||||
, _restore(
|
|
||||||
this,
|
|
||||||
object_ptr<Ui::RoundButton>(
|
|
||||||
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(
|
PanelEditIdentity::PanelEditIdentity(
|
||||||
QWidget*,
|
QWidget*,
|
||||||
not_null<PanelController*> controller,
|
not_null<PanelController*> controller,
|
||||||
|
@ -194,7 +32,6 @@ PanelEditIdentity::PanelEditIdentity(
|
||||||
const ValueMap &scanData,
|
const ValueMap &scanData,
|
||||||
std::vector<ScanInfo> &&files)
|
std::vector<ScanInfo> &&files)
|
||||||
: _controller(controller)
|
: _controller(controller)
|
||||||
, _files(std::move(files))
|
|
||||||
, _scroll(this, st::passportPanelScroll)
|
, _scroll(this, st::passportPanelScroll)
|
||||||
, _topShadow(this)
|
, _topShadow(this)
|
||||||
, _bottomShadow(this)
|
, _bottomShadow(this)
|
||||||
|
@ -202,13 +39,14 @@ PanelEditIdentity::PanelEditIdentity(
|
||||||
this,
|
this,
|
||||||
langFactory(lng_passport_save_value),
|
langFactory(lng_passport_save_value),
|
||||||
st::passportPanelSaveValue) {
|
st::passportPanelSaveValue) {
|
||||||
setupControls(data, scanData);
|
setupControls(data, scanData, std::move(files));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelEditIdentity::setupControls(
|
void PanelEditIdentity::setupControls(
|
||||||
const ValueMap &data,
|
const ValueMap &data,
|
||||||
const ValueMap &scanData) {
|
const ValueMap &scanData,
|
||||||
const auto inner = setupContent(data, scanData);
|
std::vector<ScanInfo> &&files) {
|
||||||
|
const auto inner = setupContent(data, scanData, std::move(files));
|
||||||
|
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
|
|
||||||
|
@ -219,15 +57,12 @@ void PanelEditIdentity::setupControls(
|
||||||
save();
|
save();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
_controller->scanUpdated(
|
|
||||||
) | rpl::start_with_next([=](ScanInfo &&info) {
|
|
||||||
updateScan(std::move(info));
|
|
||||||
}, lifetime());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Ui::RpWidget*> PanelEditIdentity::setupContent(
|
not_null<Ui::RpWidget*> PanelEditIdentity::setupContent(
|
||||||
const ValueMap &data,
|
const ValueMap &data,
|
||||||
const ValueMap &scanData) {
|
const ValueMap &scanData,
|
||||||
|
std::vector<ScanInfo> &&files) {
|
||||||
const auto inner = _scroll->setOwnedWidget(
|
const auto inner = _scroll->setOwnedWidget(
|
||||||
object_ptr<Ui::VerticalLayout>(this));
|
object_ptr<Ui::VerticalLayout>(this));
|
||||||
_scroll->widthValue(
|
_scroll->widthValue(
|
||||||
|
@ -235,42 +70,8 @@ not_null<Ui::RpWidget*> PanelEditIdentity::setupContent(
|
||||||
inner->resizeToWidth(width);
|
inner->resizeToWidth(width);
|
||||||
}, inner->lifetime());
|
}, inner->lifetime());
|
||||||
|
|
||||||
_scansDivider = inner->add(
|
_editScans = inner->add(
|
||||||
object_ptr<Ui::SlideWrap<BoxContentDivider>>(
|
object_ptr<EditScans>(inner, _controller, std::move(files)));
|
||||||
inner,
|
|
||||||
object_ptr<BoxContentDivider>(
|
|
||||||
inner,
|
|
||||||
st::passportFormDividerHeight)));
|
|
||||||
_scansDivider->toggle(_files.empty(), anim::type::instant);
|
|
||||||
|
|
||||||
_scansHeader = inner->add(
|
|
||||||
object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
|
|
||||||
inner,
|
|
||||||
object_ptr<Ui::FlatLabel>(
|
|
||||||
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<Ui::VerticalLayout>(inner));
|
|
||||||
for (const auto &scan : _files) {
|
|
||||||
pushScan(scan);
|
|
||||||
_scans.back()->show(anim::type::instant);
|
|
||||||
}
|
|
||||||
|
|
||||||
_scansUpload = inner->add(
|
|
||||||
object_ptr<Info::Profile::Button>(
|
|
||||||
inner,
|
|
||||||
_scansUploadTexts.events_starting_with(
|
|
||||||
uploadButtonText()
|
|
||||||
) | rpl::flatten_latest(),
|
|
||||||
st::passportUploadButton),
|
|
||||||
st::passportUploadButtonPadding);
|
|
||||||
_scansUpload->addClickHandler([=] {
|
|
||||||
chooseScan();
|
|
||||||
});
|
|
||||||
|
|
||||||
inner->add(object_ptr<BoxContentDivider>(
|
inner->add(object_ptr<BoxContentDivider>(
|
||||||
inner,
|
inner,
|
||||||
|
@ -302,53 +103,6 @@ not_null<Ui::RpWidget*> PanelEditIdentity::setupContent(
|
||||||
return inner;
|
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<Ui::SlideWrap<ScanButton>>(
|
|
||||||
_scansWrap->add(object_ptr<Ui::SlideWrap<ScanButton>>(
|
|
||||||
_scansWrap,
|
|
||||||
object_ptr<ScanButton>(
|
|
||||||
_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) {
|
void PanelEditIdentity::focusInEvent(QFocusEvent *e) {
|
||||||
_firstName->setFocusFast();
|
_firstName->setFocusFast();
|
||||||
}
|
}
|
||||||
|
@ -370,38 +124,6 @@ void PanelEditIdentity::updateControlsGeometry() {
|
||||||
_scroll->updateBars();
|
_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() {
|
void PanelEditIdentity::save() {
|
||||||
auto data = ValueMap();
|
auto data = ValueMap();
|
||||||
data.fields["first_name"] = _firstName->getLastText();
|
data.fields["first_name"] = _firstName->getLastText();
|
||||||
|
@ -410,10 +132,4 @@ void PanelEditIdentity::save() {
|
||||||
_controller->saveScope(std::move(data), std::move(scanData));
|
_controller->saveScope(std::move(data), std::move(scanData));
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<QString> PanelEditIdentity::uploadButtonText() const {
|
|
||||||
return Lang::Viewer(_files.empty()
|
|
||||||
? lng_passport_upload_scans
|
|
||||||
: lng_passport_upload_more) | Info::Profile::ToUpperValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Passport
|
} // namespace Passport
|
||||||
|
|
|
@ -9,32 +9,20 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
|
|
||||||
class BoxContentDivider;
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class InputField;
|
class InputField;
|
||||||
class VerticalLayout;
|
|
||||||
class ScrollArea;
|
class ScrollArea;
|
||||||
class FadeShadow;
|
class FadeShadow;
|
||||||
class PlainShadow;
|
class PlainShadow;
|
||||||
class FlatLabel;
|
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
template <typename Widget>
|
|
||||||
class SlideWrap;
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Info {
|
|
||||||
namespace Profile {
|
|
||||||
class Button;
|
|
||||||
} // namespace Profile
|
|
||||||
} // namespace Info
|
|
||||||
|
|
||||||
namespace Passport {
|
namespace Passport {
|
||||||
|
|
||||||
class PanelController;
|
class PanelController;
|
||||||
struct ValueMap;
|
struct ValueMap;
|
||||||
struct ScanInfo;
|
struct ScanInfo;
|
||||||
class ScanButton;
|
class EditScans;
|
||||||
|
|
||||||
class PanelEditIdentity : public Ui::RpWidget {
|
class PanelEditIdentity : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
|
@ -50,35 +38,25 @@ protected:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupControls(const ValueMap &data, const ValueMap &scanData);
|
void setupControls(
|
||||||
|
const ValueMap &data,
|
||||||
|
const ValueMap &scanData,
|
||||||
|
std::vector<ScanInfo> &&files);
|
||||||
not_null<Ui::RpWidget*> setupContent(
|
not_null<Ui::RpWidget*> setupContent(
|
||||||
const ValueMap &data,
|
const ValueMap &data,
|
||||||
const ValueMap &scanData);
|
const ValueMap &scanData,
|
||||||
|
std::vector<ScanInfo> &&files);
|
||||||
void updateControlsGeometry();
|
void updateControlsGeometry();
|
||||||
|
|
||||||
void chooseScan();
|
|
||||||
void encryptScan(const QString &path);
|
|
||||||
void encryptScanContent(QByteArray &&content);
|
|
||||||
void updateScan(ScanInfo &&info);
|
|
||||||
void pushScan(const ScanInfo &info);
|
|
||||||
|
|
||||||
rpl::producer<QString> uploadButtonText() const;
|
|
||||||
void save();
|
void save();
|
||||||
|
|
||||||
not_null<PanelController*> _controller;
|
not_null<PanelController*> _controller;
|
||||||
std::vector<ScanInfo> _files;
|
|
||||||
|
|
||||||
object_ptr<Ui::ScrollArea> _scroll;
|
object_ptr<Ui::ScrollArea> _scroll;
|
||||||
object_ptr<Ui::FadeShadow> _topShadow;
|
object_ptr<Ui::FadeShadow> _topShadow;
|
||||||
object_ptr<Ui::PlainShadow> _bottomShadow;
|
object_ptr<Ui::PlainShadow> _bottomShadow;
|
||||||
|
|
||||||
QPointer<Ui::SlideWrap<BoxContentDivider>> _scansDivider;
|
QPointer<EditScans> _editScans;
|
||||||
QPointer<Ui::SlideWrap<Ui::FlatLabel>> _scansHeader;
|
|
||||||
QPointer<Ui::VerticalLayout> _scansWrap;
|
|
||||||
std::vector<base::unique_qptr<Ui::SlideWrap<ScanButton>>> _scans;
|
|
||||||
QPointer<Info::Profile::Button> _scansUpload;
|
|
||||||
rpl::event_stream<rpl::producer<QString>> _scansUploadTexts;
|
|
||||||
|
|
||||||
QPointer<Ui::InputField> _firstName;
|
QPointer<Ui::InputField> _firstName;
|
||||||
QPointer<Ui::InputField> _lastName;
|
QPointer<Ui::InputField> _lastName;
|
||||||
|
|
||||||
|
|
|
@ -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<Ui::FadeWrapScaled<Ui::IconButton>> _delete;
|
||||||
|
object_ptr<Ui::FadeWrapScaled<Ui::RoundButton>> _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<Ui::IconButton>(this, _st.remove))
|
||||||
|
, _restore(
|
||||||
|
this,
|
||||||
|
object_ptr<Ui::RoundButton>(
|
||||||
|
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<PanelController*> controller,
|
||||||
|
std::vector<ScanInfo> &&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<Ui::SlideWrap<BoxContentDivider>>(
|
||||||
|
inner,
|
||||||
|
object_ptr<BoxContentDivider>(
|
||||||
|
inner,
|
||||||
|
st::passportFormDividerHeight)));
|
||||||
|
_divider->toggle(_files.empty(), anim::type::instant);
|
||||||
|
|
||||||
|
_header = inner->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
|
||||||
|
inner,
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
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<Ui::VerticalLayout>(inner));
|
||||||
|
for (const auto &scan : _files) {
|
||||||
|
pushScan(scan);
|
||||||
|
_rows.back()->show(anim::type::instant);
|
||||||
|
}
|
||||||
|
|
||||||
|
_upload = inner->add(
|
||||||
|
object_ptr<Info::Profile::Button>(
|
||||||
|
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<Ui::SlideWrap<ScanButton>>(
|
||||||
|
_wrap->add(object_ptr<Ui::SlideWrap<ScanButton>>(
|
||||||
|
_wrap,
|
||||||
|
object_ptr<ScanButton>(
|
||||||
|
_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<QString> EditScans::uploadButtonText() const {
|
||||||
|
return Lang::Viewer(_files.empty()
|
||||||
|
? lng_passport_upload_scans
|
||||||
|
: lng_passport_upload_more) | Info::Profile::ToUpperValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Passport
|
|
@ -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 <typename Widget>
|
||||||
|
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<PanelController*> controller,
|
||||||
|
std::vector<ScanInfo> &&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<QString> uploadButtonText() const;
|
||||||
|
|
||||||
|
not_null<PanelController*> _controller;
|
||||||
|
std::vector<ScanInfo> _files;
|
||||||
|
|
||||||
|
object_ptr<Ui::VerticalLayout> _content;
|
||||||
|
QPointer<Ui::SlideWrap<BoxContentDivider>> _divider;
|
||||||
|
QPointer<Ui::SlideWrap<Ui::FlatLabel>> _header;
|
||||||
|
QPointer<Ui::VerticalLayout> _wrap;
|
||||||
|
std::vector<base::unique_qptr<Ui::SlideWrap<ScanButton>>> _rows;
|
||||||
|
QPointer<Info::Profile::Button> _upload;
|
||||||
|
rpl::event_stream<rpl::producer<QString>> _uploadTexts;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Passport
|
|
@ -468,6 +468,8 @@
|
||||||
<(src_loc)/passport/passport_panel_details_row.h
|
<(src_loc)/passport/passport_panel_details_row.h
|
||||||
<(src_loc)/passport/passport_panel_edit_identity.cpp
|
<(src_loc)/passport/passport_panel_edit_identity.cpp
|
||||||
<(src_loc)/passport/passport_panel_edit_identity.h
|
<(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.cpp
|
||||||
<(src_loc)/passport/passport_panel_form.h
|
<(src_loc)/passport/passport_panel_form.h
|
||||||
<(src_loc)/passport/passport_panel_password.cpp
|
<(src_loc)/passport/passport_panel_password.cpp
|
||||||
|
|
Loading…
Reference in New Issue