1
0
forked from BRT/arc
arc/automation_script/script_worker.cpp
2025-04-25 15:42:51 +04:00

241 lines
8.5 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.

//
// Created by Misterio on 24.04.2025.
//
#include "script_worker.h"
#include "adb_fun.h"
#include "xml_reader.h"
#include <regex>
#include <string>
#include <thread>
#include <chrono>
// Вспомогательные функции
void wait(const int milliseconds) {
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}
// Функция для запуска скрипта с передачей параметров
void runScriptWorker(const std::string& pin, const std::string& last4digits) {
log("Запуск скрипта для ru.rshb.dbo");
if (!checkDevices()) {
log("ADB: Нет устройств");
qDebug("ADB: Нет устройств");
return;
}
if (!startApp("ru.rshb.dbo")) {
log("Не удалось запустить приложение");
qDebug("Не удалось запустить приложение");
return;
}
wait(4500);
dumpAndPullUiXml("ui_01.xml");
auto ui = parseUiDumpUsingQXml("ui_01.xml");
if (isPinScreen(ui)) {
log("Экран PIN-кода");
qDebug("Экран PIN-кода");
// Находим координаты цифр на экране и вводим ПИН
std::vector<UiElement> pinButtons = getPinButtons(ui);
for (size_t i = 0; i < pin.length(); ++i) {
char digit = pin[i];
for (const auto& el : pinButtons) {
if (el.text == std::string(1, digit)) {
tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2);
break;
}
}
}
wait(1000);
}
// Пост-логин баннеры — цикл для обработки разных состояний показов модальных окон
bool postLoginScreenFound = false;
int attempts = 5; // Максимальное количество попыток парсинга xml
while (attempts-- > 0) {
dumpAndPullUiXml("ui_02.xml");
auto ui2 = parseUiDumpUsingQXml("ui_02.xml");
// Закрытие баннеров или диалогов
if (handlePostLoginScreen(ui2)) {
postLoginScreenFound = true;
break;
}
// Проверка, если мы на главном экране
if (isMainScreen(ui2)) {
log("Главный экран подтверждён");
postLoginScreenFound = true;
break;
}
// Ждем немного перед следующим запросом дампа экрана
wait(1000);
}
if (!postLoginScreenFound) {
log("Не удалось определить пост-логин баннер.");
return;
}
// Пролистывание до кнопки "Все продукты"
swipe(1000, 2000, 1000, 1300);
wait(500);
// Нажимаем на кнопку "Все продукты"
dumpAndPullUiXml("ui_03.xml");
auto ui3 = parseUiDumpUsingQXml("ui_03.xml");
// Ищем кнопку "Все продукты" и нажимаем на неё
tapByText(ui3, "Все продукты");
wait(800);
// Шаг 6: Выбор карты на экране "Все продукты"
// Запрашиваем дамп UI для поиска карт
dumpAndPullUiXml("ui_04.xml");
auto ui4 = parseUiDumpUsingQXml("ui_04.xml");
// Определим, какую карту выбрать, например, с 4 цифрами "0823"
UiElement cardButton = findCardByLast4Digits(ui4, last4digits);
if (cardButton.text.isEmpty()) {
log("Не найдена карта с номером, содержащим " + last4digits);
return;
}
// Нажимаем на карту
tap((cardButton.x1 + cardButton.x2) / 2, (cardButton.y1 + cardButton.y2) / 2);
wait(1000);
// Нажимаем на кнопку "Оплатить"
// Запрашиваем дамп UI для поиска кнопки "Оплатить"
dumpAndPullUiXml("ui_05.xml");
auto ui5 = parseUiDumpUsingQXml("ui_05.xml");
// Ищем кнопку "Оплатить" и нажимаем на неё
UiElement payBtn = findPayButton(ui5);
if (payBtn.text.isEmpty()) {
log("Не найдена кнопка 'Оплатить'");
return;
}
// Нажимаем на кнопку "Оплатить"
tap((payBtn.x1 + payBtn.x2) / 2, (payBtn.y1 + payBtn.y2) / 2);
log("Нажата кнопка 'Оплатить'");
wait(1000);
}
// Функции для определения экранов и действий
bool isPinScreen(const std::vector<UiElement>& ui) {
for (const auto& el : ui) {
if (el.text == "Введите ПИН") {
return true;
}
}
return false;
}
std::vector<UiElement> getPinButtons(const std::vector<UiElement>& ui) {
std::vector<UiElement> pinButtons;
for (const auto& el : ui) {
if (el.text.length() == 1 && std::isdigit(el.text[0].toLatin1())) {
pinButtons.push_back(el); // Собираем все элементы с цифрами
}
}
return pinButtons;
}
void tapByText(const std::vector<UiElement>& ui, const std::string& text) {
for (const auto& el : ui) {
if (el.text == QString::fromStdString(text)) {
tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2);
break;
}
}
}
// Тап по полю ввода
void tapInputField(const std::vector<UiElement>& ui, const std::string& fieldText) {
for (const auto& el : ui) {
if (el.text == QString::fromStdString(fieldText)) {
tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2);
break;
}
}
}
// Тап по кнопке "Далее"
void tapNextButton(const std::vector<UiElement>& ui) {
for (const auto& el : ui) {
if (el.text == "Войти" || el.text == "Далее" || el.text == "Продолжить") {
tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2);
break;
}
}
}
bool handlePostLoginScreen(const std::vector<UiElement>& ui) {
for (const auto& el : ui) {
// Ищем баннеры и модальные окна, которые нужно закрыть
if (el.text == "Получайте новости с помощью" || el.text == "Не пропускайте специальные предложения и рекомендации") {
// Тапаем по пустой области
tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2);
wait(900);
return true;
}
if (el.text == "Позже" || el.text == "Окей" || el.text == "Закрыть") {
// Тапаем по кнопке закрытия или кнопке "Позже"
tap((el.x1 + el.x2) / 2, (el.y1 + el.y2) / 2);
wait(900);
return true;
}
}
return false;
}
bool isMainScreen(const std::vector<UiElement>& ui) {
for (const auto& el : ui) {
if (el.text == "Счета и карты" || el.text == "Доступно баллов") {
return true;
}
}
return false;
}
UiElement findCardByLast4Digits(const std::vector<UiElement>& ui, const std::string& last4digits) {
// Проходим по всем элементам UI, которые парсились из XML
for (const auto& el : ui) {
// Используем регулярное выражение для поиска 4 цифр в тексте
std::smatch m;
std::string str = el.text.toUtf8().constData(); // Преобразуем QString в std::string
// Если в тексте найдено совпадение с регулярным выражением для 4 цифр
if (std::regex_search(str, m, std::regex(R"(\*\*\s?(\d{4}))"))) {
// Проверяем, совпадают ли последние 4 цифры с переданными
if (m[1] == last4digits) {
// Если нашли совпадение, возвращаем элемент
return el;
}
}
}
// Если карта с такими последними цифрами не найдена, возвращаем пустой элемент
return {};
}
UiElement findPayButton(const std::vector<UiElement>& ui) {
for (const auto& el : ui) {
if (el.text == "Оплатить") {
return el;
}
}
return {};
}