1
0
forked from BRT/arc
arc/android/black/GetProfileInfoScript.cpp
slava eb14339623 Add core scripts for Black app automation and XML parsing
Implemented `CommonScript` as a base class with reusable functionality for automation workflows, including PIN input, app navigation, and server communication. Added specialized scripts like `GetCardInfoScript`, `GetProfileInfoScript`, and `LoginAndCheckAccountsScript` for card retrieval, profile parsing, and login validation. Introduced `ScreenXmlParser` for efficient XML-based UI parsing and node detection.
2026-03-11 19:45:08 +07:00

169 lines
6.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "GetProfileInfoScript.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QThread>
#include "adb/AdbUtils.h"
#include "dao/ApplicationDAO.h"
#include "dao/DeviceDAO.h"
#include "net/NetworkService.h"
namespace Black {
GetProfileInfoScript::GetProfileInfoScript(
QString deviceId,
QString appCode,
QObject *parent
) : CommonScript(parent),
m_deviceId(std::move(deviceId)),
m_appCode(std::move(appCode)) {
}
GetProfileInfoScript::~GetProfileInfoScript() = default;
void GetProfileInfoScript::doStart() {
const DeviceInfo device = DeviceDAO::getDeviceById(m_deviceId);
const ApplicationInfo app = ApplicationDAO::getApplication(m_deviceId, m_appCode);
if (device.id.isEmpty() || app.id == -1) {
m_error = "Device or app not found: " + m_deviceId + " " + m_appCode;
qCritical() << m_error;
emit finishedWithResult(m_error);
return;
}
// Читаем текущий экран
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
// Если не на домашнем экране — перезапускаем
if (!xmlScreenParser.isHomeScreen()) {
qDebug() << "[Black::GetProfileInfo] Not on home screen, restarting app...";
if (!runAppAndGoToHomeScreen(device.id, app.package, app.pinCode,
device.screenWidth, device.screenHeight)) {
m_error = "Cannot reach home screen: " + m_deviceId + " " + m_appCode;
qWarning() << m_error;
AdbUtils::tryToKillApplication(m_deviceId, app.package);
emit finishedWithResult(m_error);
return;
}
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
}
// 1. Тапаем по кнопке "¡Hola!" (аватар с именем) на домашнем экране
Node holaNode = xmlScreenParser.findHolaButton();
if (holaNode.isEmpty()) {
m_error = "Cannot find Hola button on home screen: " + m_deviceId;
qWarning() << m_error;
AdbUtils::tryToKillApplication(m_deviceId, app.package);
emit finishedWithResult(m_error);
return;
}
// Парсим имя и баланс с домашнего экрана
const QString fullName = xmlScreenParser.parseUserNameFromHomeScreen();
const double balance = xmlScreenParser.parseBalanceFromHomeScreen();
qDebug() << "[Black::GetProfileInfo] fullName from home:" << fullName << "balance:" << balance;
// Сохраняем баланс
ApplicationDAO::updateAmount(app.id, balance);
AdbUtils::makeTap(m_deviceId, holaNode.x(), holaNode.y());
QThread::msleep(2000);
// 2. Ждём боковое меню
bool sideMenuFound = false;
for (int attempt = 0; attempt < 5; ++attempt) {
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
if (xmlScreenParser.isSideMenu()) {
sideMenuFound = true;
break;
}
QThread::msleep(1000);
}
if (!sideMenuFound) {
m_error = "Side menu not detected: " + m_deviceId;
qWarning() << m_error;
AdbUtils::tryToKillApplication(m_deviceId, app.package);
emit finishedWithResult(m_error);
return;
}
// 3. Тапаем "Tu Información"
Node tuInfoNode = xmlScreenParser.findNodeByContentDesc(QString::fromUtf8("Tu Información"));
if (tuInfoNode.isEmpty()) {
m_error = "Cannot find Tu Información button: " + m_deviceId;
qWarning() << m_error;
AdbUtils::tryToKillApplication(m_deviceId, app.package);
emit finishedWithResult(m_error);
return;
}
AdbUtils::makeTap(m_deviceId, tuInfoNode.x(), tuInfoNode.y());
QThread::msleep(2500);
// 4. Ждём страницу профиля "Tu información"
bool profileFound = false;
for (int attempt = 0; attempt < 5; ++attempt) {
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
if (xmlScreenParser.isProfilePage()) {
profileFound = true;
break;
}
QThread::msleep(1000);
}
if (!profileFound) {
m_error = "Profile page not detected: " + m_deviceId;
qWarning() << m_error;
AdbUtils::tryToKillApplication(m_deviceId, app.package);
emit finishedWithResult(m_error);
return;
}
// 5. Парсим данные профиля (первый экран: nombre, apellido, email)
const QString nombre = xmlScreenParser.parseProfileNombre();
const QString apellido = xmlScreenParser.parseProfileApellido();
const QString email = xmlScreenParser.parseProfileEmail();
// 6. Скроллим вниз чтобы увидеть телефон
const int x = device.screenWidth / 2;
const int fromY = device.screenHeight * 3 / 4;
const int toY = device.screenHeight / 4;
AdbUtils::makeSwipe(m_deviceId, x, fromY, x, toY);
QThread::msleep(1500);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
const QString phone = xmlScreenParser.parseProfilePhone();
// Собираем полное имя: "имя фамилия"
QString parsedFullName;
if (!nombre.isEmpty() && !apellido.isEmpty()) {
parsedFullName = nombre + " " + apellido;
} else if (!nombre.isEmpty()) {
parsedFullName = nombre;
} else {
parsedFullName = fullName; // fallback с домашнего экрана
}
qDebug() << "[Black::GetProfileInfo] nombre:" << nombre
<< "apellido:" << apellido
<< "email:" << email
<< "phone:" << phone
<< "fullName:" << parsedFullName;
// 7. Сохраняем в БД
if (!ApplicationDAO::updateProfileInfo(app.id, parsedFullName, phone, email)) {
qWarning() << "[Black::GetProfileInfo] Failed to save profile info to DB";
}
// 7. Создаём bank profile если нет
createBankProfileIfNeeded(m_deviceId, m_appCode);
AdbUtils::tryToKillApplication(m_deviceId, app.package);
emit finishedWithResult(m_error);
}
} // namespace Black