mirror of https://github.com/procxx/kepka.git
Allow to add selfie in passport.
This commit is contained in:
parent
11fd757e99
commit
ccb57a6d69
|
@ -1548,6 +1548,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_passport_scan_index" = "Scan {index}";
|
"lng_passport_scan_index" = "Scan {index}";
|
||||||
"lng_passport_upload_scans" = "Upload scans";
|
"lng_passport_upload_scans" = "Upload scans";
|
||||||
"lng_passport_upload_more" = "Upload additional scans";
|
"lng_passport_upload_more" = "Upload additional scans";
|
||||||
|
"lng_passport_selfie_title" = "Selfie";
|
||||||
|
"lng_passport_selfie_name" = "Photo";
|
||||||
|
"lng_passport_selfie_description" = "Take a picture of yourself holding hour document.";
|
||||||
|
"lng_passport_upload_selfie" = "Upload selfie";
|
||||||
"lng_passport_personal_details" = "Personal details";
|
"lng_passport_personal_details" = "Personal details";
|
||||||
"lng_passport_choose_image" = "Choose scan image";
|
"lng_passport_choose_image" = "Choose scan image";
|
||||||
"lng_passport_delete_scan_undo" = "Undo";
|
"lng_passport_delete_scan_undo" = "Undo";
|
||||||
|
|
|
@ -242,6 +242,18 @@ bool FormController::validateValueSecrets(Value &value) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (value.selfie) {
|
||||||
|
auto &file = *value.selfie;
|
||||||
|
file.secret = DecryptValueSecret(
|
||||||
|
file.encryptedSecret,
|
||||||
|
_secret,
|
||||||
|
file.hash);
|
||||||
|
if (file.secret.empty()) {
|
||||||
|
LOG(("API Error: Could not decrypt selfie secret. "
|
||||||
|
"Forgetting files and data :("));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,8 +278,53 @@ void FormController::uploadScan(
|
||||||
nonconst,
|
nonconst,
|
||||||
File(),
|
File(),
|
||||||
nullptr);
|
nullptr);
|
||||||
const auto fileId = rand_value<uint64>();
|
|
||||||
auto &file = nonconst->filesInEdit.back();
|
auto &file = nonconst->filesInEdit.back();
|
||||||
|
encryptFile(file, std::move(content), [=](UploadScanData &&result) {
|
||||||
|
Expects(fileIndex >= 0 && fileIndex < nonconst->filesInEdit.size());
|
||||||
|
|
||||||
|
uploadEncryptedFile(
|
||||||
|
nonconst->filesInEdit[fileIndex],
|
||||||
|
std::move(result));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void FormController::deleteScan(
|
||||||
|
not_null<const Value*> value,
|
||||||
|
int fileIndex) {
|
||||||
|
scanDeleteRestore(value, fileIndex, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FormController::restoreScan(
|
||||||
|
not_null<const Value*> value,
|
||||||
|
int fileIndex) {
|
||||||
|
scanDeleteRestore(value, fileIndex, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FormController::uploadSelfie(
|
||||||
|
not_null<const Value*> value,
|
||||||
|
QByteArray &&content) {
|
||||||
|
const auto nonconst = findValue(value);
|
||||||
|
nonconst->selfieInEdit = EditFile{ nonconst, File(), nullptr };
|
||||||
|
auto &file = *nonconst->selfieInEdit;
|
||||||
|
encryptFile(file, std::move(content), [=](UploadScanData &&result) {
|
||||||
|
uploadEncryptedFile(
|
||||||
|
*nonconst->selfieInEdit,
|
||||||
|
std::move(result));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void FormController::deleteSelfie(not_null<const Value*> value) {
|
||||||
|
selfieDeleteRestore(value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FormController::restoreSelfie(not_null<const Value*> value) {
|
||||||
|
selfieDeleteRestore(value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FormController::prepareFile(
|
||||||
|
EditFile &file,
|
||||||
|
const QByteArray &content) {
|
||||||
|
const auto fileId = rand_value<uint64>();
|
||||||
file.fields.size = content.size();
|
file.fields.size = content.size();
|
||||||
file.fields.id = fileId;
|
file.fields.id = fileId;
|
||||||
file.fields.dcId = MTP::maindc();
|
file.fields.dcId = MTP::maindc();
|
||||||
|
@ -277,17 +334,14 @@ void FormController::uploadScan(
|
||||||
file.fields.downloadOffset = file.fields.size;
|
file.fields.downloadOffset = file.fields.size;
|
||||||
|
|
||||||
_scanUpdated.fire(&file);
|
_scanUpdated.fire(&file);
|
||||||
|
|
||||||
encryptScan(nonconst, fileIndex, std::move(content));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::encryptScan(
|
void FormController::encryptFile(
|
||||||
not_null<Value*> value,
|
EditFile &file,
|
||||||
int fileIndex,
|
QByteArray &&content,
|
||||||
QByteArray &&content) {
|
base::lambda<void(UploadScanData &&result)> callback) {
|
||||||
Expects(fileIndex >= 0 && fileIndex < value->filesInEdit.size());
|
prepareFile(file, content);
|
||||||
|
|
||||||
const auto &file = value->filesInEdit[fileIndex];
|
|
||||||
const auto weak = std::weak_ptr<bool>(file.guard);
|
const auto weak = std::weak_ptr<bool>(file.guard);
|
||||||
crl::async([
|
crl::async([
|
||||||
=,
|
=,
|
||||||
|
@ -309,27 +363,12 @@ void FormController::encryptScan(
|
||||||
result.md5checksum.data());
|
result.md5checksum.data());
|
||||||
crl::on_main([=, encrypted = std::move(result)]() mutable {
|
crl::on_main([=, encrypted = std::move(result)]() mutable {
|
||||||
if (weak.lock()) {
|
if (weak.lock()) {
|
||||||
uploadEncryptedScan(
|
callback(std::move(encrypted));
|
||||||
value ,
|
|
||||||
fileIndex,
|
|
||||||
std::move(encrypted));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::deleteScan(
|
|
||||||
not_null<const Value*> value,
|
|
||||||
int fileIndex) {
|
|
||||||
scanDeleteRestore(value, fileIndex, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FormController::restoreScan(
|
|
||||||
not_null<const Value*> value,
|
|
||||||
int fileIndex) {
|
|
||||||
scanDeleteRestore(value, fileIndex, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FormController::scanDeleteRestore(
|
void FormController::scanDeleteRestore(
|
||||||
not_null<const Value*> value,
|
not_null<const Value*> value,
|
||||||
int fileIndex,
|
int fileIndex,
|
||||||
|
@ -342,6 +381,17 @@ void FormController::scanDeleteRestore(
|
||||||
_scanUpdated.fire(&file);
|
_scanUpdated.fire(&file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FormController::selfieDeleteRestore(
|
||||||
|
not_null<const Value*> value,
|
||||||
|
bool deleted) {
|
||||||
|
Expects(value->selfieInEdit.has_value());
|
||||||
|
|
||||||
|
const auto nonconst = findValue(value);
|
||||||
|
auto &file = *nonconst->selfieInEdit;
|
||||||
|
file.deleted = deleted;
|
||||||
|
_scanUpdated.fire(&file);
|
||||||
|
}
|
||||||
|
|
||||||
void FormController::subscribeToUploader() {
|
void FormController::subscribeToUploader() {
|
||||||
if (_uploaderSubscriptions) {
|
if (_uploaderSubscriptions) {
|
||||||
return;
|
return;
|
||||||
|
@ -365,15 +415,11 @@ void FormController::subscribeToUploader() {
|
||||||
}, _uploaderSubscriptions);
|
}, _uploaderSubscriptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::uploadEncryptedScan(
|
void FormController::uploadEncryptedFile(
|
||||||
not_null<Value*> value,
|
EditFile &file,
|
||||||
int fileIndex,
|
|
||||||
UploadScanData &&data) {
|
UploadScanData &&data) {
|
||||||
Expects(fileIndex >= 0 && fileIndex < value->filesInEdit.size());
|
|
||||||
|
|
||||||
subscribeToUploader();
|
subscribeToUploader();
|
||||||
|
|
||||||
auto &file = value->filesInEdit[fileIndex];
|
|
||||||
file.uploadData = std::make_unique<UploadScanData>(std::move(data));
|
file.uploadData = std::make_unique<UploadScanData>(std::move(data));
|
||||||
|
|
||||||
auto prepared = std::make_shared<FileLoadResult>(
|
auto prepared = std::make_shared<FileLoadResult>(
|
||||||
|
@ -548,27 +594,43 @@ void FormController::startValueEdit(not_null<const Value*> value) {
|
||||||
if (savingValue(nonconst)) {
|
if (savingValue(nonconst)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loadFiles(nonconst->files);
|
for (auto &file : nonconst->files) {
|
||||||
|
loadFile(file);
|
||||||
|
}
|
||||||
|
if (nonconst->selfie) {
|
||||||
|
loadFile(*nonconst->selfie);
|
||||||
|
}
|
||||||
nonconst->filesInEdit = ranges::view::all(
|
nonconst->filesInEdit = ranges::view::all(
|
||||||
nonconst->files
|
nonconst->files
|
||||||
) | ranges::view::transform([=](const File &file) {
|
) | ranges::view::transform([=](const File &file) {
|
||||||
return EditFile(nonconst, file, nullptr);
|
return EditFile(nonconst, file, nullptr);
|
||||||
}) | ranges::to_vector;
|
}) | ranges::to_vector;
|
||||||
|
|
||||||
|
if (nonconst->selfie) {
|
||||||
|
nonconst->selfieInEdit = EditFile(
|
||||||
|
nonconst,
|
||||||
|
*nonconst->selfie,
|
||||||
|
nullptr);
|
||||||
|
} else {
|
||||||
|
nonconst->selfieInEdit = base::none;
|
||||||
|
}
|
||||||
|
|
||||||
nonconst->data.parsedInEdit = nonconst->data.parsed;
|
nonconst->data.parsedInEdit = nonconst->data.parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FormController::loadFiles(std::vector<File> &files) {
|
void FormController::loadFile(File &file) {
|
||||||
for (auto &file : files) {
|
|
||||||
if (!file.image.isNull()) {
|
if (!file.image.isNull()) {
|
||||||
file.downloadOffset = file.size;
|
file.downloadOffset = file.size;
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto key = FileKey{ file.id, file.dcId };
|
const auto key = FileKey{ file.id, file.dcId };
|
||||||
const auto i = _fileLoaders.find(key);
|
const auto i = _fileLoaders.find(key);
|
||||||
if (i == _fileLoaders.end()) {
|
if (i != _fileLoaders.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
file.downloadOffset = 0;
|
file.downloadOffset = 0;
|
||||||
const auto [i, ok] = _fileLoaders.emplace(
|
const auto [j, ok] = _fileLoaders.emplace(
|
||||||
key,
|
key,
|
||||||
std::make_unique<mtpFileLoader>(
|
std::make_unique<mtpFileLoader>(
|
||||||
file.dcId,
|
file.dcId,
|
||||||
|
@ -581,7 +643,7 @@ void FormController::loadFiles(std::vector<File> &files) {
|
||||||
LoadToCacheAsWell,
|
LoadToCacheAsWell,
|
||||||
LoadFromCloudOrLocal,
|
LoadFromCloudOrLocal,
|
||||||
false));
|
false));
|
||||||
const auto loader = i->second.get();
|
const auto loader = j->second.get();
|
||||||
loader->connect(loader, &mtpFileLoader::progress, [=] {
|
loader->connect(loader, &mtpFileLoader::progress, [=] {
|
||||||
if (loader->finished()) {
|
if (loader->finished()) {
|
||||||
fileLoadDone(key, loader->bytes());
|
fileLoadDone(key, loader->bytes());
|
||||||
|
@ -594,8 +656,6 @@ void FormController::loadFiles(std::vector<File> &files) {
|
||||||
});
|
});
|
||||||
loader->start();
|
loader->start();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FormController::fileLoadDone(FileKey key, const QByteArray &bytes) {
|
void FormController::fileLoadDone(FileKey key, const QByteArray &bytes) {
|
||||||
if (const auto [value, file] = findFile(key); file != nullptr) {
|
if (const auto [value, file] = findFile(key); file != nullptr) {
|
||||||
|
@ -666,6 +726,7 @@ void FormController::clearValueEdit(not_null<Value*> value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
value->filesInEdit.clear();
|
value->filesInEdit.clear();
|
||||||
|
value->selfieInEdit = base::none;
|
||||||
value->data.encryptedSecretInEdit.clear();
|
value->data.encryptedSecretInEdit.clear();
|
||||||
value->data.hashInEdit.clear();
|
value->data.hashInEdit.clear();
|
||||||
value->data.parsedInEdit = ValueMap();
|
value->data.parsedInEdit = ValueMap();
|
||||||
|
@ -787,7 +848,6 @@ void FormController::saveEncryptedValue(not_null<Value*> value) {
|
||||||
inputFiles.push_back(inputFile(file));
|
inputFiles.push_back(inputFile(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (value->data.secret.empty()) {
|
if (value->data.secret.empty()) {
|
||||||
value->data.secret = GenerateSecretBytes();
|
value->data.secret = GenerateSecretBytes();
|
||||||
}
|
}
|
||||||
|
@ -890,9 +950,18 @@ void FormController::sendSaveRequest(
|
||||||
value->saveRequestId = 0;
|
value->saveRequestId = 0;
|
||||||
|
|
||||||
const auto &data = result.c_secureValue();
|
const auto &data = result.c_secureValue();
|
||||||
value->files = parseFiles(
|
value->files = data.has_files()
|
||||||
|
? parseFiles(
|
||||||
data.vfiles.v,
|
data.vfiles.v,
|
||||||
base::take(value->filesInEdit));
|
base::take(value->filesInEdit))
|
||||||
|
: std::vector<File>();
|
||||||
|
auto selfiesInEdit = std::vector<EditFile>();
|
||||||
|
if (auto selfie = base::take(value->selfieInEdit)) {
|
||||||
|
selfiesInEdit.push_back(std::move(*selfie));
|
||||||
|
}
|
||||||
|
value->selfie = data.has_selfie()
|
||||||
|
? parseFile(data.vselfie, selfiesInEdit)
|
||||||
|
: base::none;
|
||||||
value->data.encryptedSecret = std::move(
|
value->data.encryptedSecret = std::move(
|
||||||
value->data.encryptedSecretInEdit);
|
value->data.encryptedSecretInEdit);
|
||||||
value->data.parsed = std::move(value->data.parsedInEdit);
|
value->data.parsed = std::move(value->data.parsedInEdit);
|
||||||
|
@ -1110,32 +1179,40 @@ auto FormController::parseFiles(
|
||||||
auto result = std::vector<File>();
|
auto result = std::vector<File>();
|
||||||
result.reserve(data.size());
|
result.reserve(data.size());
|
||||||
|
|
||||||
auto index = 0;
|
|
||||||
for (const auto &file : data) {
|
for (const auto &file : data) {
|
||||||
switch (file.type()) {
|
if (auto normal = parseFile(file, editData)) {
|
||||||
case mtpc_secureFileEmpty: {
|
result.push_back(std::move(*normal));
|
||||||
|
|
||||||
} break;
|
|
||||||
case mtpc_secureFile: {
|
|
||||||
const auto &fields = file.c_secureFile();
|
|
||||||
auto normal = File();
|
|
||||||
normal.id = fields.vid.v;
|
|
||||||
normal.accessHash = fields.vaccess_hash.v;
|
|
||||||
normal.size = fields.vsize.v;
|
|
||||||
normal.date = fields.vdate.v;
|
|
||||||
normal.dcId = fields.vdc_id.v;
|
|
||||||
normal.hash = bytes::make_vector(fields.vfile_hash.v);
|
|
||||||
normal.encryptedSecret = bytes::make_vector(fields.vsecret.v);
|
|
||||||
fillDownloadedFile(normal, editData);
|
|
||||||
result.push_back(std::move(normal));
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
++index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto FormController::parseFile(
|
||||||
|
const MTPSecureFile &data,
|
||||||
|
const std::vector<EditFile> &editData) const
|
||||||
|
-> base::optional<File> {
|
||||||
|
switch (data.type()) {
|
||||||
|
case mtpc_secureFileEmpty:
|
||||||
|
return base::none;
|
||||||
|
|
||||||
|
case mtpc_secureFile: {
|
||||||
|
const auto &fields = data.c_secureFile();
|
||||||
|
auto result = File();
|
||||||
|
result.id = fields.vid.v;
|
||||||
|
result.accessHash = fields.vaccess_hash.v;
|
||||||
|
result.size = fields.vsize.v;
|
||||||
|
result.date = fields.vdate.v;
|
||||||
|
result.dcId = fields.vdc_id.v;
|
||||||
|
result.hash = bytes::make_vector(fields.vfile_hash.v);
|
||||||
|
result.encryptedSecret = bytes::make_vector(fields.vsecret.v);
|
||||||
|
fillDownloadedFile(result, editData);
|
||||||
|
return result;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
Unexpected("Type in FormController::parseFile.");
|
||||||
|
}
|
||||||
|
|
||||||
void FormController::fillDownloadedFile(
|
void FormController::fillDownloadedFile(
|
||||||
File &destination,
|
File &destination,
|
||||||
const std::vector<EditFile> &source) const {
|
const std::vector<EditFile> &source) const {
|
||||||
|
@ -1180,6 +1257,9 @@ auto FormController::parseValue(
|
||||||
if (data.has_files()) {
|
if (data.has_files()) {
|
||||||
result.files = parseFiles(data.vfiles.v);
|
result.files = parseFiles(data.vfiles.v);
|
||||||
}
|
}
|
||||||
|
if (data.has_selfie()) {
|
||||||
|
result.selfie = parseFile(data.vselfie);
|
||||||
|
}
|
||||||
if (data.has_plain_data()) {
|
if (data.has_plain_data()) {
|
||||||
switch (data.vplain_data.type()) {
|
switch (data.vplain_data.type()) {
|
||||||
case mtpc_securePlainPhone: {
|
case mtpc_securePlainPhone: {
|
||||||
|
@ -1197,35 +1277,53 @@ auto FormController::parseValue(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FormController::findEditFile(const FullMsgId &fullId) -> EditFile* {
|
auto FormController::findEditFile(const FullMsgId &fullId) -> EditFile* {
|
||||||
|
const auto found = [&](const EditFile &file) {
|
||||||
|
return (file.uploadData && file.uploadData->fullId == fullId);
|
||||||
|
};
|
||||||
for (auto &[type, value] : _form.values) {
|
for (auto &[type, value] : _form.values) {
|
||||||
for (auto &file : value.filesInEdit) {
|
for (auto &file : value.filesInEdit) {
|
||||||
if (file.uploadData && file.uploadData->fullId == fullId) {
|
if (found(file)) {
|
||||||
return &file;
|
return &file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (value.selfieInEdit && found(*value.selfieInEdit)) {
|
||||||
|
return &*value.selfieInEdit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FormController::findEditFile(const FileKey &key) -> EditFile* {
|
auto FormController::findEditFile(const FileKey &key) -> EditFile* {
|
||||||
|
const auto found = [&](const EditFile &file) {
|
||||||
|
return (file.fields.dcId == key.dcId && file.fields.id == key.id);
|
||||||
|
};
|
||||||
for (auto &[type, value] : _form.values) {
|
for (auto &[type, value] : _form.values) {
|
||||||
for (auto &file : value.filesInEdit) {
|
for (auto &file : value.filesInEdit) {
|
||||||
if (file.fields.dcId == key.dcId && file.fields.id == key.id) {
|
if (found(file)) {
|
||||||
return &file;
|
return &file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (value.selfieInEdit && found(*value.selfieInEdit)) {
|
||||||
|
return &*value.selfieInEdit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FormController::findFile(const FileKey &key)
|
auto FormController::findFile(const FileKey &key)
|
||||||
-> std::pair<Value*, File*> {
|
-> std::pair<Value*, File*> {
|
||||||
|
const auto found = [&](const File &file) {
|
||||||
|
return (file.dcId == key.dcId) && (file.id == key.id);
|
||||||
|
};
|
||||||
for (auto &[type, value] : _form.values) {
|
for (auto &[type, value] : _form.values) {
|
||||||
for (auto &file : value.files) {
|
for (auto &file : value.files) {
|
||||||
if (file.dcId == key.dcId && file.id == key.id) {
|
if (found(file)) {
|
||||||
return { &value, &file };
|
return { &value, &file };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (value.selfie && found(*value.selfie)) {
|
||||||
|
return { &value, &*value.selfie };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return { nullptr, nullptr };
|
return { nullptr, nullptr };
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,6 +212,9 @@ public:
|
||||||
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);
|
||||||
|
void uploadSelfie(not_null<const Value*> value, QByteArray &&content);
|
||||||
|
void deleteSelfie(not_null<const Value*> value);
|
||||||
|
void restoreSelfie(not_null<const Value*> value);
|
||||||
|
|
||||||
rpl::producer<> secretReadyEvents() const;
|
rpl::producer<> secretReadyEvents() const;
|
||||||
|
|
||||||
|
@ -257,6 +260,9 @@ private:
|
||||||
std::vector<File> parseFiles(
|
std::vector<File> parseFiles(
|
||||||
const QVector<MTPSecureFile> &data,
|
const QVector<MTPSecureFile> &data,
|
||||||
const std::vector<EditFile> &editData = {}) const;
|
const std::vector<EditFile> &editData = {}) const;
|
||||||
|
base::optional<File> parseFile(
|
||||||
|
const MTPSecureFile &data,
|
||||||
|
const std::vector<EditFile> &editData = {}) const;
|
||||||
void fillDownloadedFile(
|
void fillDownloadedFile(
|
||||||
File &destination,
|
File &destination,
|
||||||
const std::vector<EditFile> &source) const;
|
const std::vector<EditFile> &source) const;
|
||||||
|
@ -275,25 +281,33 @@ private:
|
||||||
bool validateValueSecrets(Value &value);
|
bool validateValueSecrets(Value &value);
|
||||||
void resetValue(Value &value);
|
void resetValue(Value &value);
|
||||||
|
|
||||||
void loadFiles(std::vector<File> &files);
|
void loadFile(File &file);
|
||||||
void fileLoadDone(FileKey key, const QByteArray &bytes);
|
void fileLoadDone(FileKey key, const QByteArray &bytes);
|
||||||
void fileLoadProgress(FileKey key, int offset);
|
void fileLoadProgress(FileKey key, int offset);
|
||||||
void fileLoadFail(FileKey key);
|
void fileLoadFail(FileKey key);
|
||||||
void generateSecret(bytes::const_span password);
|
void generateSecret(bytes::const_span password);
|
||||||
|
|
||||||
void subscribeToUploader();
|
void subscribeToUploader();
|
||||||
void encryptScan(
|
void encryptFile(
|
||||||
not_null<Value*> value,
|
EditFile &file,
|
||||||
int fileIndex,
|
QByteArray &&content,
|
||||||
QByteArray &&content);
|
base::lambda<void(UploadScanData &&result)> callback);
|
||||||
void uploadEncryptedScan(
|
void prepareFile(
|
||||||
not_null<Value*> value,
|
EditFile &file,
|
||||||
int fileIndex,
|
const QByteArray &content);
|
||||||
|
void uploadEncryptedFile(
|
||||||
|
EditFile &file,
|
||||||
UploadScanData &&data);
|
UploadScanData &&data);
|
||||||
void scanUploadDone(const Storage::UploadSecureDone &data);
|
void scanUploadDone(const Storage::UploadSecureDone &data);
|
||||||
void scanUploadProgress(const Storage::UploadSecureProgress &data);
|
void scanUploadProgress(const Storage::UploadSecureProgress &data);
|
||||||
void scanUploadFail(const FullMsgId &fullId);
|
void scanUploadFail(const FullMsgId &fullId);
|
||||||
void scanDeleteRestore(not_null<const Value*> value, int fileIndex, bool deleted);
|
void scanDeleteRestore(
|
||||||
|
not_null<const Value*> value,
|
||||||
|
int fileIndex,
|
||||||
|
bool deleted);
|
||||||
|
void selfieDeleteRestore(
|
||||||
|
not_null<const Value*> value,
|
||||||
|
bool deleted);
|
||||||
|
|
||||||
QString getPhoneFromValue(not_null<const Value*> value) const;
|
QString getPhoneFromValue(not_null<const Value*> value) const;
|
||||||
QString getEmailFromValue(not_null<const Value*> value) const;
|
QString getEmailFromValue(not_null<const Value*> value) const;
|
||||||
|
|
|
@ -356,7 +356,8 @@ QString PanelController::defaultPhoneNumber() const {
|
||||||
|
|
||||||
void PanelController::uploadScan(QByteArray &&content) {
|
void PanelController::uploadScan(QByteArray &&content) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editScopeFilesIndex >= 0);
|
Expects(_editScopeFilesIndex >= 0
|
||||||
|
&& _editScopeFilesIndex < _editScope->files.size());
|
||||||
|
|
||||||
_form->uploadScan(
|
_form->uploadScan(
|
||||||
_editScope->files[_editScopeFilesIndex],
|
_editScope->files[_editScopeFilesIndex],
|
||||||
|
@ -365,7 +366,8 @@ void PanelController::uploadScan(QByteArray &&content) {
|
||||||
|
|
||||||
void PanelController::deleteScan(int fileIndex) {
|
void PanelController::deleteScan(int fileIndex) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editScopeFilesIndex >= 0);
|
Expects(_editScopeFilesIndex >= 0
|
||||||
|
&& _editScopeFilesIndex < _editScope->files.size());
|
||||||
|
|
||||||
_form->deleteScan(
|
_form->deleteScan(
|
||||||
_editScope->files[_editScopeFilesIndex],
|
_editScope->files[_editScopeFilesIndex],
|
||||||
|
@ -374,13 +376,45 @@ void PanelController::deleteScan(int fileIndex) {
|
||||||
|
|
||||||
void PanelController::restoreScan(int fileIndex) {
|
void PanelController::restoreScan(int fileIndex) {
|
||||||
Expects(_editScope != nullptr);
|
Expects(_editScope != nullptr);
|
||||||
Expects(_editScopeFilesIndex >= 0);
|
Expects(_editScopeFilesIndex >= 0
|
||||||
|
&& _editScopeFilesIndex < _editScope->files.size());
|
||||||
|
|
||||||
_form->restoreScan(
|
_form->restoreScan(
|
||||||
_editScope->files[_editScopeFilesIndex],
|
_editScope->files[_editScopeFilesIndex],
|
||||||
fileIndex);
|
fileIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PanelController::uploadSelfie(QByteArray &&content) {
|
||||||
|
Expects(_editScope != nullptr);
|
||||||
|
Expects(_editScopeFilesIndex >= 0
|
||||||
|
&& _editScopeFilesIndex < _editScope->files.size());
|
||||||
|
Expects(_editScope->selfieRequired);
|
||||||
|
|
||||||
|
_form->uploadSelfie(
|
||||||
|
_editScope->files[_editScopeFilesIndex],
|
||||||
|
std::move(content));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PanelController::deleteSelfie() {
|
||||||
|
Expects(_editScope != nullptr);
|
||||||
|
Expects(_editScopeFilesIndex >= 0
|
||||||
|
&& _editScopeFilesIndex < _editScope->files.size());
|
||||||
|
Expects(_editScope->selfieRequired);
|
||||||
|
|
||||||
|
_form->deleteSelfie(
|
||||||
|
_editScope->files[_editScopeFilesIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PanelController::restoreSelfie() {
|
||||||
|
Expects(_editScope != nullptr);
|
||||||
|
Expects(_editScopeFilesIndex >= 0
|
||||||
|
&& _editScopeFilesIndex < _editScope->files.size());
|
||||||
|
Expects(_editScope->selfieRequired);
|
||||||
|
|
||||||
|
_form->restoreSelfie(
|
||||||
|
_editScope->files[_editScopeFilesIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
rpl::producer<ScanInfo> PanelController::scanUpdated() const {
|
rpl::producer<ScanInfo> PanelController::scanUpdated() const {
|
||||||
return _form->scanUpdated(
|
return _form->scanUpdated(
|
||||||
) | rpl::filter([=](not_null<const EditFile*> file) {
|
) | rpl::filter([=](not_null<const EditFile*> file) {
|
||||||
|
@ -422,11 +456,17 @@ ScanInfo PanelController::collectScanInfo(const EditFile &file) const {
|
||||||
return formatDownloadText(0, file.fields.size);
|
return formatDownloadText(0, file.fields.size);
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
auto isSelfie = (_editScope != nullptr)
|
||||||
|
&& (_editScopeFilesIndex >= 0)
|
||||||
|
&& (file.value == _editScope->files[_editScopeFilesIndex])
|
||||||
|
&& (_editScope->files[_editScopeFilesIndex]->selfieInEdit.has_value())
|
||||||
|
&& (&file == &*_editScope->files[_editScopeFilesIndex]->selfieInEdit);
|
||||||
return {
|
return {
|
||||||
FileKey{ file.fields.id, file.fields.dcId },
|
FileKey{ file.fields.id, file.fields.dcId },
|
||||||
status,
|
status,
|
||||||
file.fields.image,
|
file.fields.image,
|
||||||
file.deleted };
|
file.deleted,
|
||||||
|
isSelfie };
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PanelController::getDefaultContactValue(Scope::Type type) const {
|
QString PanelController::getDefaultContactValue(Scope::Type type) const {
|
||||||
|
@ -594,7 +634,10 @@ void PanelController::editScope(int index, int filesIndex) {
|
||||||
_editScope->files[_editScopeFilesIndex]->type),
|
_editScope->files[_editScopeFilesIndex]->type),
|
||||||
_editScope->fields->data.parsedInEdit,
|
_editScope->fields->data.parsedInEdit,
|
||||||
_editScope->files[_editScopeFilesIndex]->data.parsedInEdit,
|
_editScope->files[_editScopeFilesIndex]->data.parsedInEdit,
|
||||||
valueFiles(*_editScope->files[_editScopeFilesIndex]))
|
valueFiles(*_editScope->files[_editScopeFilesIndex]),
|
||||||
|
(_editScope->selfieRequired
|
||||||
|
? valueSelfie(*_editScope->files[_editScopeFilesIndex])
|
||||||
|
: nullptr))
|
||||||
: object_ptr<PanelEditDocument>(
|
: object_ptr<PanelEditDocument>(
|
||||||
_panel.get(),
|
_panel.get(),
|
||||||
this,
|
this,
|
||||||
|
@ -735,6 +778,15 @@ std::vector<ScanInfo> PanelController::valueFiles(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ScanInfo> PanelController::valueSelfie(
|
||||||
|
const Value &value) const {
|
||||||
|
if (value.selfieInEdit) {
|
||||||
|
return std::make_unique<ScanInfo>(
|
||||||
|
collectScanInfo(*value.selfieInEdit));
|
||||||
|
}
|
||||||
|
return std::make_unique<ScanInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
void PanelController::cancelValueEdit() {
|
void PanelController::cancelValueEdit() {
|
||||||
if (const auto scope = base::take(_editScope)) {
|
if (const auto scope = base::take(_editScope)) {
|
||||||
_form->cancelValueEdit(scope->fields);
|
_form->cancelValueEdit(scope->fields);
|
||||||
|
|
|
@ -20,6 +20,7 @@ struct ScanInfo {
|
||||||
QString status;
|
QString status;
|
||||||
QImage thumb;
|
QImage thumb;
|
||||||
bool deleted = false;
|
bool deleted = false;
|
||||||
|
bool selfie = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,6 +55,9 @@ public:
|
||||||
void uploadScan(QByteArray &&content);
|
void uploadScan(QByteArray &&content);
|
||||||
void deleteScan(int fileIndex);
|
void deleteScan(int fileIndex);
|
||||||
void restoreScan(int fileIndex);
|
void restoreScan(int fileIndex);
|
||||||
|
void uploadSelfie(QByteArray &&content);
|
||||||
|
void deleteSelfie();
|
||||||
|
void restoreSelfie();
|
||||||
rpl::producer<ScanInfo> scanUpdated() const;
|
rpl::producer<ScanInfo> scanUpdated() const;
|
||||||
|
|
||||||
QString defaultEmail() const;
|
QString defaultEmail() const;
|
||||||
|
@ -92,6 +96,7 @@ private:
|
||||||
void requestScopeFilesType(int index);
|
void requestScopeFilesType(int index);
|
||||||
void cancelValueEdit();
|
void cancelValueEdit();
|
||||||
std::vector<ScanInfo> valueFiles(const Value &value) const;
|
std::vector<ScanInfo> valueFiles(const Value &value) const;
|
||||||
|
std::unique_ptr<ScanInfo> valueSelfie(const Value &value) const;
|
||||||
void processValueSaveFinished(not_null<const Value*> value);
|
void processValueSaveFinished(not_null<const Value*> value);
|
||||||
void processVerificationNeeded(not_null<const Value*> value);
|
void processVerificationNeeded(not_null<const Value*> value);
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,8 @@ PanelEditDocument::PanelEditDocument(
|
||||||
Scheme scheme,
|
Scheme scheme,
|
||||||
const ValueMap &data,
|
const ValueMap &data,
|
||||||
const ValueMap &scanData,
|
const ValueMap &scanData,
|
||||||
std::vector<ScanInfo> &&files)
|
std::vector<ScanInfo> &&files,
|
||||||
|
std::unique_ptr<ScanInfo> &&selfie)
|
||||||
: _controller(controller)
|
: _controller(controller)
|
||||||
, _scheme(std::move(scheme))
|
, _scheme(std::move(scheme))
|
||||||
, _scroll(this, st::passportPanelScroll)
|
, _scroll(this, st::passportPanelScroll)
|
||||||
|
@ -145,7 +146,7 @@ PanelEditDocument::PanelEditDocument(
|
||||||
this,
|
this,
|
||||||
langFactory(lng_passport_save_value),
|
langFactory(lng_passport_save_value),
|
||||||
st::passportPanelSaveValue) {
|
st::passportPanelSaveValue) {
|
||||||
setupControls(data, &scanData, std::move(files));
|
setupControls(data, &scanData, std::move(files), std::move(selfie));
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelEditDocument::PanelEditDocument(
|
PanelEditDocument::PanelEditDocument(
|
||||||
|
@ -162,14 +163,19 @@ PanelEditDocument::PanelEditDocument(
|
||||||
this,
|
this,
|
||||||
langFactory(lng_passport_save_value),
|
langFactory(lng_passport_save_value),
|
||||||
st::passportPanelSaveValue) {
|
st::passportPanelSaveValue) {
|
||||||
setupControls(data, nullptr, {});
|
setupControls(data, nullptr, {}, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelEditDocument::setupControls(
|
void PanelEditDocument::setupControls(
|
||||||
const ValueMap &data,
|
const ValueMap &data,
|
||||||
const ValueMap *scanData,
|
const ValueMap *scanData,
|
||||||
std::vector<ScanInfo> &&files) {
|
std::vector<ScanInfo> &&files,
|
||||||
const auto inner = setupContent(data, scanData, std::move(files));
|
std::unique_ptr<ScanInfo> &&selfie) {
|
||||||
|
const auto inner = setupContent(
|
||||||
|
data,
|
||||||
|
scanData,
|
||||||
|
std::move(files),
|
||||||
|
std::move(selfie));
|
||||||
|
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
|
|
||||||
|
@ -185,7 +191,8 @@ void PanelEditDocument::setupControls(
|
||||||
not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
||||||
const ValueMap &data,
|
const ValueMap &data,
|
||||||
const ValueMap *scanData,
|
const ValueMap *scanData,
|
||||||
std::vector<ScanInfo> &&files) {
|
std::vector<ScanInfo> &&files,
|
||||||
|
std::unique_ptr<ScanInfo> &&selfie) {
|
||||||
const auto inner = _scroll->setOwnedWidget(
|
const auto inner = _scroll->setOwnedWidget(
|
||||||
object_ptr<Ui::VerticalLayout>(this));
|
object_ptr<Ui::VerticalLayout>(this));
|
||||||
_scroll->widthValue(
|
_scroll->widthValue(
|
||||||
|
@ -199,12 +206,14 @@ not_null<Ui::RpWidget*> PanelEditDocument::setupContent(
|
||||||
inner,
|
inner,
|
||||||
_controller,
|
_controller,
|
||||||
_scheme.scansHeader,
|
_scheme.scansHeader,
|
||||||
std::move(files)));
|
std::move(files),
|
||||||
}
|
std::move(selfie)));
|
||||||
|
} else {
|
||||||
inner->add(object_ptr<BoxContentDivider>(
|
inner->add(object_ptr<BoxContentDivider>(
|
||||||
inner,
|
inner,
|
||||||
st::passportFormDividerHeight));
|
st::passportFormDividerHeight));
|
||||||
|
}
|
||||||
|
|
||||||
inner->add(
|
inner->add(
|
||||||
object_ptr<Ui::FlatLabel>(
|
object_ptr<Ui::FlatLabel>(
|
||||||
inner,
|
inner,
|
||||||
|
|
|
@ -52,7 +52,8 @@ public:
|
||||||
Scheme scheme,
|
Scheme scheme,
|
||||||
const ValueMap &data,
|
const ValueMap &data,
|
||||||
const ValueMap &scanData,
|
const ValueMap &scanData,
|
||||||
std::vector<ScanInfo> &&files);
|
std::vector<ScanInfo> &&files,
|
||||||
|
std::unique_ptr<ScanInfo> &&selfie);
|
||||||
PanelEditDocument(
|
PanelEditDocument(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<PanelController*> controller,
|
not_null<PanelController*> controller,
|
||||||
|
@ -70,11 +71,13 @@ private:
|
||||||
void setupControls(
|
void setupControls(
|
||||||
const ValueMap &data,
|
const ValueMap &data,
|
||||||
const ValueMap *scanData,
|
const ValueMap *scanData,
|
||||||
std::vector<ScanInfo> &&files);
|
std::vector<ScanInfo> &&files,
|
||||||
|
std::unique_ptr<ScanInfo> &&selfie);
|
||||||
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);
|
std::vector<ScanInfo> &&files,
|
||||||
|
std::unique_ptr<ScanInfo> &&selfie);
|
||||||
void updateControlsGeometry();
|
void updateControlsGeometry();
|
||||||
|
|
||||||
Result collect() const;
|
Result collect() const;
|
||||||
|
|
|
@ -8,6 +8,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_controller.h"
|
#include "passport/passport_panel_controller.h"
|
||||||
|
#include "passport/passport_panel_details_row.h"
|
||||||
#include "info/profile/info_profile_button.h"
|
#include "info/profile/info_profile_button.h"
|
||||||
#include "info/profile/info_profile_values.h"
|
#include "info/profile/info_profile_values.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
|
@ -185,10 +186,12 @@ EditScans::EditScans(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<PanelController*> controller,
|
not_null<PanelController*> controller,
|
||||||
const QString &header,
|
const QString &header,
|
||||||
std::vector<ScanInfo> &&files)
|
std::vector<ScanInfo> &&files,
|
||||||
|
std::unique_ptr<ScanInfo> &&selfie)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _controller(controller)
|
, _controller(controller)
|
||||||
, _files(std::move(files))
|
, _files(std::move(files))
|
||||||
|
, _selfie(std::move(selfie))
|
||||||
, _content(this) {
|
, _content(this) {
|
||||||
setupContent(header);
|
setupContent(header);
|
||||||
}
|
}
|
||||||
|
@ -233,6 +236,48 @@ void EditScans::setupContent(const QString &header) {
|
||||||
_upload->addClickHandler([=] {
|
_upload->addClickHandler([=] {
|
||||||
chooseScan();
|
chooseScan();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
inner->add(object_ptr<BoxContentDivider>(
|
||||||
|
inner,
|
||||||
|
st::passportFormDividerHeight));
|
||||||
|
|
||||||
|
if (_selfie) {
|
||||||
|
_selfieHeader = inner->add(
|
||||||
|
object_ptr<Ui::SlideWrap<Ui::FlatLabel>>(
|
||||||
|
inner,
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
inner,
|
||||||
|
lang(lng_passport_selfie_title),
|
||||||
|
Ui::FlatLabel::InitType::Simple,
|
||||||
|
st::passportFormHeader),
|
||||||
|
st::passportUploadHeaderPadding));
|
||||||
|
_selfieHeader->toggle(_selfie->key.id != 0, anim::type::instant);
|
||||||
|
_selfieWrap = inner->add(object_ptr<Ui::VerticalLayout>(inner));
|
||||||
|
if (_selfie->key.id) {
|
||||||
|
createSelfieRow(*_selfie);
|
||||||
|
}
|
||||||
|
_selfieUpload = inner->add(
|
||||||
|
object_ptr<Info::Profile::Button>(
|
||||||
|
inner,
|
||||||
|
Lang::Viewer(
|
||||||
|
lng_passport_upload_selfie
|
||||||
|
) | Info::Profile::ToUpperValue(),
|
||||||
|
st::passportUploadButton),
|
||||||
|
st::passportUploadButtonPadding);
|
||||||
|
_selfieUpload->addClickHandler([=] {
|
||||||
|
chooseSelfie();
|
||||||
|
});
|
||||||
|
|
||||||
|
inner->add(object_ptr<PanelLabel>(
|
||||||
|
inner,
|
||||||
|
object_ptr<Ui::FlatLabel>(
|
||||||
|
_content,
|
||||||
|
lang(lng_passport_selfie_description),
|
||||||
|
Ui::FlatLabel::InitType::Simple,
|
||||||
|
st::passportFormLabel),
|
||||||
|
st::passportFormLabelPadding));
|
||||||
|
}
|
||||||
|
|
||||||
_controller->scanUpdated(
|
_controller->scanUpdated(
|
||||||
) | rpl::start_with_next([=](ScanInfo &&info) {
|
) | rpl::start_with_next([=](ScanInfo &&info) {
|
||||||
updateScan(std::move(info));
|
updateScan(std::move(info));
|
||||||
|
@ -250,11 +295,32 @@ void EditScans::setupContent(const QString &header) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditScans::updateScan(ScanInfo &&info) {
|
void EditScans::updateScan(ScanInfo &&info) {
|
||||||
|
const auto updateRow = [&](
|
||||||
|
not_null<ScanButton*> button,
|
||||||
|
const ScanInfo &info) {
|
||||||
|
button->setStatus(info.status);
|
||||||
|
button->setImage(info.thumb);
|
||||||
|
button->setDeleted(info.deleted);
|
||||||
|
};
|
||||||
|
if (info.selfie) {
|
||||||
|
Assert(info.key.id != 0);
|
||||||
|
Assert(_selfie != nullptr);
|
||||||
|
if (_selfie->key.id) {
|
||||||
|
updateRow(_selfieRow->entity(), info);
|
||||||
|
} else {
|
||||||
|
createSelfieRow(info);
|
||||||
|
_selfieWrap->resizeToWidth(width());
|
||||||
|
_selfieRow->show(anim::type::normal);
|
||||||
|
_selfieHeader->show(anim::type::normal);
|
||||||
|
}
|
||||||
|
*_selfie = std::move(info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto i = ranges::find(_files, info.key, [](const ScanInfo &file) {
|
const auto i = ranges::find(_files, info.key, [](const ScanInfo &file) {
|
||||||
return file.key;
|
return file.key;
|
||||||
});
|
});
|
||||||
if (i != _files.end()) {
|
if (i != _files.end()) {
|
||||||
*i = info;
|
*i = std::move(info);
|
||||||
const auto scan = _rows[i - _files.begin()]->entity();
|
const auto scan = _rows[i - _files.begin()]->entity();
|
||||||
scan->setStatus(i->status);
|
scan->setStatus(i->status);
|
||||||
scan->setImage(i->thumb);
|
scan->setImage(i->thumb);
|
||||||
|
@ -270,20 +336,33 @@ void EditScans::updateScan(ScanInfo &&info) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditScans::createSelfieRow(const ScanInfo &info) {
|
||||||
|
_selfieRow = createScan(
|
||||||
|
_selfieWrap,
|
||||||
|
info,
|
||||||
|
lang(lng_passport_selfie_name));
|
||||||
|
const auto row = _selfieRow->entity();
|
||||||
|
|
||||||
|
row->deleteClicks(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_controller->deleteSelfie();
|
||||||
|
}, row->lifetime());
|
||||||
|
|
||||||
|
row->restoreClicks(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
_controller->restoreSelfie();
|
||||||
|
}, row->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
void EditScans::pushScan(const ScanInfo &info) {
|
void EditScans::pushScan(const ScanInfo &info) {
|
||||||
const auto index = _rows.size();
|
const auto index = _rows.size();
|
||||||
_rows.push_back(base::unique_qptr<Ui::SlideWrap<ScanButton>>(
|
_rows.push_back(createScan(
|
||||||
_wrap->add(object_ptr<Ui::SlideWrap<ScanButton>>(
|
|
||||||
_wrap,
|
_wrap,
|
||||||
object_ptr<ScanButton>(
|
info,
|
||||||
_wrap,
|
lng_passport_scan_index(lt_index, QString::number(index + 1))));
|
||||||
st::passportScanRow,
|
|
||||||
lng_passport_scan_index(lt_index, QString::number(index + 1)),
|
|
||||||
info.status,
|
|
||||||
info.deleted)))));
|
|
||||||
_rows.back()->hide(anim::type::instant);
|
_rows.back()->hide(anim::type::instant);
|
||||||
|
|
||||||
const auto scan = _rows.back()->entity();
|
const auto scan = _rows.back()->entity();
|
||||||
scan->setImage(info.thumb);
|
|
||||||
|
|
||||||
scan->deleteClicks(
|
scan->deleteClicks(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
|
@ -296,12 +375,35 @@ void EditScans::pushScan(const ScanInfo &info) {
|
||||||
}, scan->lifetime());
|
}, scan->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base::unique_qptr<Ui::SlideWrap<ScanButton>> EditScans::createScan(
|
||||||
|
not_null<Ui::VerticalLayout*> parent,
|
||||||
|
const ScanInfo &info,
|
||||||
|
const QString &name) {
|
||||||
|
auto result = base::unique_qptr<Ui::SlideWrap<ScanButton>>(
|
||||||
|
parent->add(object_ptr<Ui::SlideWrap<ScanButton>>(
|
||||||
|
parent,
|
||||||
|
object_ptr<ScanButton>(
|
||||||
|
parent,
|
||||||
|
st::passportScanRow,
|
||||||
|
name,
|
||||||
|
info.status,
|
||||||
|
info.deleted))));
|
||||||
|
result->entity()->setImage(info.thumb);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void EditScans::chooseScan() {
|
void EditScans::chooseScan() {
|
||||||
ChooseScan(base::lambda_guarded(this, [=](QByteArray &&content) {
|
ChooseScan(base::lambda_guarded(this, [=](QByteArray &&content) {
|
||||||
_controller->uploadScan(std::move(content));
|
_controller->uploadScan(std::move(content));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditScans::chooseSelfie() {
|
||||||
|
ChooseScan(base::lambda_guarded(this, [=](QByteArray &&content) {
|
||||||
|
_controller->uploadSelfie(std::move(content));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
void EditScans::ChooseScan(base::lambda<void(QByteArray&&)> callback) {
|
void EditScans::ChooseScan(base::lambda<void(QByteArray&&)> callback) {
|
||||||
const auto filter = FileDialog::AllFilesFilter()
|
const auto filter = FileDialog::AllFilesFilter()
|
||||||
+ qsl(";;Image files (*")
|
+ qsl(";;Image files (*")
|
||||||
|
|
|
@ -36,20 +36,28 @@ public:
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<PanelController*> controller,
|
not_null<PanelController*> controller,
|
||||||
const QString &header,
|
const QString &header,
|
||||||
std::vector<ScanInfo> &&files);
|
std::vector<ScanInfo> &&files,
|
||||||
|
std::unique_ptr<ScanInfo> &&selfie);
|
||||||
|
|
||||||
static void ChooseScan(base::lambda<void(QByteArray&&)> callback);
|
static void ChooseScan(base::lambda<void(QByteArray&&)> callback);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupContent(const QString &header);
|
void setupContent(const QString &header);
|
||||||
void chooseScan();
|
void chooseScan();
|
||||||
|
void chooseSelfie();
|
||||||
void updateScan(ScanInfo &&info);
|
void updateScan(ScanInfo &&info);
|
||||||
void pushScan(const ScanInfo &info);
|
void pushScan(const ScanInfo &info);
|
||||||
|
void createSelfieRow(const ScanInfo &info);
|
||||||
|
base::unique_qptr<Ui::SlideWrap<ScanButton>> createScan(
|
||||||
|
not_null<Ui::VerticalLayout*> parent,
|
||||||
|
const ScanInfo &info,
|
||||||
|
const QString &name);
|
||||||
|
|
||||||
rpl::producer<QString> uploadButtonText() const;
|
rpl::producer<QString> uploadButtonText() const;
|
||||||
|
|
||||||
not_null<PanelController*> _controller;
|
not_null<PanelController*> _controller;
|
||||||
std::vector<ScanInfo> _files;
|
std::vector<ScanInfo> _files;
|
||||||
|
std::unique_ptr<ScanInfo> _selfie;
|
||||||
|
|
||||||
object_ptr<Ui::VerticalLayout> _content;
|
object_ptr<Ui::VerticalLayout> _content;
|
||||||
QPointer<Ui::SlideWrap<BoxContentDivider>> _divider;
|
QPointer<Ui::SlideWrap<BoxContentDivider>> _divider;
|
||||||
|
@ -59,6 +67,11 @@ private:
|
||||||
QPointer<Info::Profile::Button> _upload;
|
QPointer<Info::Profile::Button> _upload;
|
||||||
rpl::event_stream<rpl::producer<QString>> _uploadTexts;
|
rpl::event_stream<rpl::producer<QString>> _uploadTexts;
|
||||||
|
|
||||||
|
QPointer<Ui::SlideWrap<Ui::FlatLabel>> _selfieHeader;
|
||||||
|
QPointer<Ui::VerticalLayout> _selfieWrap;
|
||||||
|
base::unique_qptr<Ui::SlideWrap<ScanButton>> _selfieRow;
|
||||||
|
QPointer<Info::Profile::Button> _selfieUpload;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Passport
|
} // namespace Passport
|
||||||
|
|
Loading…
Reference in New Issue