diff --git a/android/dushanbe/GetLastTransactionsScript.cpp b/android/dushanbe/GetLastTransactionsScript.cpp index 751877c..ba46dfe 100644 --- a/android/dushanbe/GetLastTransactionsScript.cpp +++ b/android/dushanbe/GetLastTransactionsScript.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -16,6 +17,24 @@ #include "AppLogger.h" #include + +// Душанбе показывает суммы как "100,50", "100.50 TJS", "1 000,50", +// "1 000.50 TJS" и т.п. Голый QString::toDouble на таком вернёт 0, +// потому что требует, чтобы вся строка была валидным числом. +static double parseDushanbeAmount(const QString &raw) { + QString s = raw; + s.remove(QRegularExpression(R"([^\d,.\-])")); + s.replace(',', '.'); + const int firstDot = s.indexOf('.'); + if (firstDot >= 0) { + QString head = s.left(firstDot); + QString tail = s.mid(firstDot + 1); + tail.remove('.'); + s = head + '.' + tail; + } + return s.toDouble(); +} + static QString recognizeTextFromImage(const QByteArray &pngData) { auto *api = new tesseract::TessBaseAPI(); if (api->Init(QCoreApplication::applicationDirPath().toUtf8().constData(), "rus+eng")) { @@ -649,9 +668,72 @@ void GetLastTransactionsScript::doStart() { if (interrupted()) { m_error = "Interrupted"; emit finishedWithResult(m_error); return; } xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight); - // 1) Старый blob-формат (до 3.2.33): "Успешный платеж" / "Поступление" — - // одна нода с ключами и значениями через \n. + // 1) Bottom-sheet формат (3.2.33, см. assets/dushanbe/3.2.33/tx_detail.xml): + // одна нода со всем content-desc через \n. Лейблы без двоеточий, сумма — + // отдельной строкой со знаком сразу после даты+времени. + // "Успешный платёж\n21.05.2026 16:58:32\n-10\nКарта\n...\nПолучатель\n...\nЗакрыть" for (const Node &n : xmlScreenParser.findAllNodes()) { + const QString cd = n.contentDesc; + if (!cd.contains(QString::fromUtf8("Карта"))) continue; + if (!cd.contains(QString::fromUtf8("Получатель"))) continue; + if (!cd.contains(QString::fromUtf8("Операция"))) continue; + const QStringList lines = cd.split('\n', Qt::SkipEmptyParts); + if (lines.size() < 6) continue; + + // lines[0] — заголовок: "Успешный платёж" / "Поступление" / ... + if (lines[0].contains(QString::fromUtf8("Успешн")) + || lines[0].contains(QString::fromUtf8("Поступление")) + || lines[0].contains(QString::fromUtf8("выполнен"))) { + detail.status = QString::fromUtf8("Успешный"); + } + // lines[1] — "dd.MM.yyyy HH:mm:ss" + { + static const QRegularExpression reDt( + R"((\d{2}\.\d{2}\.\d{4})\s+(\d{2}:\d{2}:\d{2}))"); + const auto m = reDt.match(lines[1]); + if (m.hasMatch()) { + detail.date = m.captured(1); + detail.time = m.captured(2); + } + } + // lines[2] — сумма со знаком: "-10" / "30" / "30.50" / "1 000,50". + detail.amount = parseDushanbeAmount(lines[2]); + + // Дальше — пары label/value; значение может быть multi-line (Получатель). + // На сервер шлём первую строку получателя — таков сложившийся контракт. + static const QSet labels{ + QString::fromUtf8("Карта"), + QString::fromUtf8("Получатель"), + QString::fromUtf8("Операция"), + QString::fromUtf8("Дата"), + QString::fromUtf8("Время"), + QString::fromUtf8("Закрыть"), + QString::fromUtf8("Назад"), + }; + for (int i = 3; i < lines.size(); ++i) { + const QString lbl = lines[i].trimmed(); + if (!labels.contains(lbl)) continue; + QStringList vals; + for (int j = i + 1; j < lines.size(); ++j) { + const QString cand = lines[j].trimmed(); + if (labels.contains(cand)) break; + vals << cand; + } + if (vals.isEmpty()) continue; + if (lbl == QString::fromUtf8("Получатель")) { + detail.receiverAccount = vals.first(); + } else if (lbl == QString::fromUtf8("Дата") && detail.date.isEmpty()) { + detail.date = vals.first(); + } else if (lbl == QString::fromUtf8("Время") && detail.time.isEmpty()) { + detail.time = vals.first(); + } + } + detailLoaded = true; + break; + } + // 2) Старый blob-формат (до 3.2.33): "Успешный платеж" / "Поступление" — + // одна нода с ключами и значениями через \n. + if (!detailLoaded) for (const Node &n : xmlScreenParser.findAllNodes()) { if (!n.contentDesc.contains(QString::fromUtf8("Дата"))) continue; if (!n.contentDesc.contains(QString::fromUtf8("Время"))) continue; const QStringList lines = n.contentDesc.split('\n'); @@ -663,7 +745,7 @@ void GetLastTransactionsScript::doStart() { if (key == QString::fromUtf8("Получатель")) { detail.receiverAccount = val; } else if (key == QString::fromUtf8("Сумма")) { - detail.amount = val.toDouble(); + detail.amount = parseDushanbeAmount(val); } else if (key == QString::fromUtf8("Дата")) { detail.date = val; } else if (key == QString::fromUtf8("Время")) { @@ -673,7 +755,8 @@ void GetLastTransactionsScript::doStart() { detailLoaded = true; break; } - // 2) Новый split-формат (с 3.2.33): лейблы и значения в отдельных View-нодах. + // 3) Split-формат: лейблы (с ':') и значения в отдельных View-нодах + // на одной Y-полосе. Промежуточная версия между blob и bottom-sheet. if (!detailLoaded) { const QMap pairs = xmlScreenParser.parseLabelValuePairs(); const QString d = pairs.value(QString::fromUtf8("Дата")); @@ -682,11 +765,11 @@ void GetLastTransactionsScript::doStart() { detail.date = d; detail.time = t; detail.receiverAccount = pairs.value(QString::fromUtf8("Получатель")); - detail.amount = pairs.value(QString::fromUtf8("Сумма")).toDouble(); + detail.amount = parseDushanbeAmount(pairs.value(QString::fromUtf8("Сумма"))); if (detail.amount == 0.0) { - detail.amount = pairs.value(QString::fromUtf8("К зачислению")).toDouble(); + detail.amount = parseDushanbeAmount(pairs.value(QString::fromUtf8("К зачислению"))); } - detail.fee = pairs.value(QString::fromUtf8("Комиссия")).toDouble(); + detail.fee = parseDushanbeAmount(pairs.value(QString::fromUtf8("Комиссия"))); detail.operationId = pairs.value(QString::fromUtf8("Номер операции")); detail.status = pairs.value(QString::fromUtf8("Статус")); detailLoaded = true; diff --git a/assets/dushanbe/3.2.33/tx_detail.jpg b/assets/dushanbe/3.2.33/tx_detail.jpg new file mode 100644 index 0000000..d55a1cd Binary files /dev/null and b/assets/dushanbe/3.2.33/tx_detail.jpg differ diff --git a/assets/dushanbe/3.2.33/tx_detail.xml b/assets/dushanbe/3.2.33/tx_detail.xml new file mode 100644 index 0000000..5a0096d --- /dev/null +++ b/assets/dushanbe/3.2.33/tx_detail.xml @@ -0,0 +1 @@ + \ No newline at end of file