Include appVersion and clientVersion in error reporting for task failures. Add fallback logic for bottom navigation taps in GetLastTransactionsScript using icon-based detection.
This commit is contained in:
parent
b486e922b3
commit
3391591e33
@ -1,7 +1,6 @@
|
|||||||
#include "GetLastTransactionsScript.h"
|
#include "GetLastTransactionsScript.h"
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QHash>
|
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
@ -437,34 +436,51 @@ void GetLastTransactionsScript::doStart() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QPoint GetLastTransactionsScript::bottomNavPoint(const QString &label, const DeviceInfo &device) {
|
QPoint GetLastTransactionsScript::bottomNavPoint(const QString &label, const DeviceInfo &device) {
|
||||||
const Node n = xmlScreenParser.findNodeByContentDesc(label);
|
// 1) Норма: у таба есть реальные bounds в нижней полосе экрана. Проверка
|
||||||
// Реальные bounds принимаем только если они «вменяемые» для НИЖНЕГО меню:
|
// «центр в нижних 80% высоты» отсекает и вырожденные [0,0][0,0], и
|
||||||
// непустой узел, ненулевой центр И центр в нижней полосе экрана (>= 80%
|
// НЕнулевые-но-негодные координаты (одноимённый элемент не в нав-баре).
|
||||||
// высоты). Это отсекает не только вырожденные [0,0][0,0] (Infinix XOS), но и
|
const Node lbl = xmlScreenParser.findNodeByContentDesc(label);
|
||||||
// НЕнулевые, но негодные координаты — напр. одноимённый элемент не в нав-баре
|
if (!lbl.isEmpty() && lbl.x() > 0
|
||||||
// или частичные bounds. Иначе нав-бар у самого низа, центр таба ~95% высоты.
|
&& lbl.y() >= static_cast<int>(device.screenHeight * 0.80))
|
||||||
if (!n.isEmpty() && n.x() > 0 && n.y() >= static_cast<int>(device.screenHeight * 0.80))
|
return {lbl.x(), lbl.y()};
|
||||||
return {n.x(), n.y()};
|
|
||||||
|
|
||||||
// Узел нав-таба отсутствует или негоден. На части устройств
|
// 2) Лейбл нав-таба вырожден ([0,0][0,0] — гибридный UI, напр. Infinix XOS не
|
||||||
// (наблюдалось на Infinix X669D, app 3.2.41 — гибридный UI) uiautomator не
|
// отдаёт bounds нижнего меню). Но ИКОНКИ табов имеют реальные координаты.
|
||||||
// отдаёт bounds нижнего меню, хотя оно отрисовано в полосе у самого низа
|
// Берём самый нижний ряд небольших нод и в нём крайнюю по X: История —
|
||||||
// экрана (ниже всего дерева доступности). Тапаем по геометрии: 5 равных
|
// самая правая иконка, Главная — самая левая (FAB по центру никогда не
|
||||||
// слотов — Главная · Переводы · [FAB] · MiniApps · История; центр слота —
|
// крайний; контентные плитки выше нижнего ряда и отсекаются по y2). Это
|
||||||
// доля ширины, высота — у самого низа экрана.
|
// фактические координаты → не зависит от размера экрана, плотности и
|
||||||
static const QHash<QString, double> kFx{
|
// высоты системной навигации Android (её фикс-высота в dp ломала бы доли).
|
||||||
{QString::fromUtf8("Главная"), 0.10},
|
const bool rightmost = (label == QString::fromUtf8("История"));
|
||||||
{QString::fromUtf8("Переводы"), 0.30},
|
const bool leftmost = (label == QString::fromUtf8("Главная"));
|
||||||
{QString::fromUtf8("MiniApps"), 0.70},
|
if (rightmost || leftmost) {
|
||||||
{QString::fromUtf8("История"), 0.90},
|
const int H = device.screenHeight, W = device.screenWidth;
|
||||||
};
|
const auto nodes = xmlScreenParser.findAllNodes();
|
||||||
const auto it = kFx.constFind(label);
|
auto isNavIcon = [&](const Node &n) {
|
||||||
if (it == kFx.constEnd()) return {-1, -1};
|
return n.x1() >= 0 && n.width() > 0 && n.height() >= 12
|
||||||
const int x = static_cast<int>(device.screenWidth * it.value());
|
&& n.width() <= W / 3 && n.y() >= H / 2; // не контейнер, нижняя половина
|
||||||
const int y = static_cast<int>(device.screenHeight * 0.95);
|
};
|
||||||
qWarning() << "[Dushanbe::GetLastTransactions] nav tab" << label
|
int rowBottom = -1;
|
||||||
<< "has no usable bounds — geometric fallback tap at" << x << y;
|
for (const Node &n : nodes)
|
||||||
return {x, y};
|
if (isNavIcon(n)) rowBottom = qMax(rowBottom, n.y2());
|
||||||
|
if (rowBottom > 0) {
|
||||||
|
const int tol = qMax(8, H / 100); // «тот же ряд» — у самой нижней кромки
|
||||||
|
Node pick;
|
||||||
|
for (const Node &n : nodes) {
|
||||||
|
if (!isNavIcon(n) || n.y2() < rowBottom - tol) continue;
|
||||||
|
if (pick.isEmpty()
|
||||||
|
|| (rightmost && n.x() > pick.x())
|
||||||
|
|| (leftmost && n.x() < pick.x()))
|
||||||
|
pick = n;
|
||||||
|
}
|
||||||
|
if (!pick.isEmpty()) {
|
||||||
|
qWarning() << "[Dushanbe::GetLastTransactions] nav tab" << label
|
||||||
|
<< "— icon-row fallback tap at" << pick.x() << pick.y();
|
||||||
|
return {pick.x(), pick.y()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {-1, -1};
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetLastTransactionsScript::searchAll(
|
void GetLastTransactionsScript::searchAll(
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QSettings>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QTimeZone>
|
#include <QTimeZone>
|
||||||
@ -230,27 +231,35 @@ static void sendTaskError(const QString &type, const QString &materialId, const
|
|||||||
// api-токен общий на нескольких операторов — по нему не отличить, чей
|
// api-токен общий на нескольких операторов — по нему не отличить, чей
|
||||||
// профиль упал. Резолвим банковский профиль по accountId и пишем его
|
// профиль упал. Резолвим банковский профиль по accountId и пишем его
|
||||||
// серверный UUID + материал + телефон профиля.
|
// серверный UUID + материал + телефон профиля.
|
||||||
QString profileUuid, profilePhone;
|
QString profileUuid, profilePhone, appVersion;
|
||||||
if (accountId > 0) {
|
if (accountId > 0) {
|
||||||
const MaterialInfo acc = MaterialDAO::getAccountById(accountId);
|
const MaterialInfo acc = MaterialDAO::getAccountById(accountId);
|
||||||
if (acc.id != -1) {
|
if (acc.id != -1) {
|
||||||
const BankProfileInfo app = BankProfileDAO::getApplication(acc.deviceId, acc.appCode);
|
const BankProfileInfo app = BankProfileDAO::getApplication(acc.deviceId, acc.appCode);
|
||||||
profileUuid = app.bankProfileId;
|
profileUuid = app.bankProfileId;
|
||||||
profilePhone = app.phone;
|
profilePhone = app.phone;
|
||||||
|
appVersion = app.appVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const QString desktopId = SettingsDAO::get("desktop_id");
|
const QString desktopId = SettingsDAO::get("desktop_id");
|
||||||
|
// Версия самого ARC-десктопа (клиента), не банковского приложения.
|
||||||
|
const QString clientVersion =
|
||||||
|
QSettings("config.ini", QSettings::IniFormat).value("common/version").toString();
|
||||||
QStringList lines;
|
QStringList lines;
|
||||||
lines << QStringLiteral("<b>[TASK_ERROR] [%1] [%2]</b>")
|
lines << QStringLiteral("<b>[TASK_ERROR] [%1] [%2]</b>")
|
||||||
.arg(type.toHtmlEscaped(), bankName.toUpper().toHtmlEscaped());
|
.arg(type.toHtmlEscaped(), bankName.toUpper().toHtmlEscaped());
|
||||||
if (!desktopId.isEmpty())
|
if (!desktopId.isEmpty())
|
||||||
lines << QStringLiteral("Desktop: %1").arg(desktopId.toHtmlEscaped());
|
lines << QStringLiteral("Desktop: %1").arg(desktopId.toHtmlEscaped());
|
||||||
|
if (!clientVersion.isEmpty())
|
||||||
|
lines << QStringLiteral("DesktopVersion: %1").arg(clientVersion.toHtmlEscaped());
|
||||||
if (!profileUuid.isEmpty())
|
if (!profileUuid.isEmpty())
|
||||||
lines << QStringLiteral("Profile: %1").arg(profileUuid.toHtmlEscaped());
|
lines << QStringLiteral("Profile: %1").arg(profileUuid.toHtmlEscaped());
|
||||||
if (!materialId.isEmpty())
|
if (!materialId.isEmpty())
|
||||||
lines << QStringLiteral("Material: %1").arg(materialId.toHtmlEscaped());
|
lines << QStringLiteral("Material: %1").arg(materialId.toHtmlEscaped());
|
||||||
if (!profilePhone.isEmpty())
|
if (!profilePhone.isEmpty())
|
||||||
lines << QStringLiteral("Phone: %1").arg(profilePhone.toHtmlEscaped());
|
lines << QStringLiteral("Phone: %1").arg(profilePhone.toHtmlEscaped());
|
||||||
|
if (!appVersion.isEmpty())
|
||||||
|
lines << QStringLiteral("AppVersion: %1").arg(appVersion.toHtmlEscaped());
|
||||||
lines << QStringLiteral("Error: %1").arg(description.toHtmlEscaped());
|
lines << QStringLiteral("Error: %1").arg(description.toHtmlEscaped());
|
||||||
const QString message = lines.join(QStringLiteral("\n"));
|
const QString message = lines.join(QStringLiteral("\n"));
|
||||||
sendMonitoringLog("error", "task_error", message, screenshot, eventId);
|
sendMonitoringLog("error", "task_error", message, screenshot, eventId);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user