533 lines
22 KiB
C++
533 lines
22 KiB
C++
#include "DeviceWidget.h"
|
||
#include <QVBoxLayout>
|
||
#include <QLabel>
|
||
#include <QPixmap>
|
||
#include <QImage>
|
||
#include <QPushButton>
|
||
#include <QCoreApplication>
|
||
#include <QJsonDocument>
|
||
#include <QJsonObject>
|
||
#include <QPointer>
|
||
#include <QPropertyAnimation>
|
||
#include <QGraphicsScene>
|
||
#include <QMessageBox>
|
||
|
||
#include "bank/AccountSettingsWindow.h"
|
||
#include "bank/BankSetupWizard.h"
|
||
#include "dao/BankProfileDAO.h"
|
||
#include "bank/BankSettingsWindow.h"
|
||
#include "DeviceSettingsWindow.h"
|
||
#include "dao/BankProfileDAO.h"
|
||
#include "dao/MaterialDAO.h"
|
||
#include "dao/DeviceDAO.h"
|
||
#include "dao/EventDAO.h"
|
||
#include "dao/SettingsDAO.h"
|
||
#include "db/BankProfileInfo.h"
|
||
#include "net/NetworkService.h"
|
||
#include "adb/AdbUtils.h"
|
||
#include <QThread>
|
||
#include <QNetworkAccessManager>
|
||
#include <QNetworkRequest>
|
||
#include <QNetworkReply>
|
||
#include <QHttpMultiPart>
|
||
#include <QBuffer>
|
||
#include <QSslSocket>
|
||
#include <QSslConfiguration>
|
||
#include <QTimer>
|
||
|
||
|
||
QString getColorByStatus(const BankProfileInfo &app) {
|
||
if (!app.install) {
|
||
return "black";
|
||
}
|
||
if (app.status == "active") {
|
||
if (!app.pinCodeChecked) {
|
||
return "orange";
|
||
}
|
||
return "green";
|
||
} else if (app.status == "off") {
|
||
return "red";
|
||
} else {
|
||
return "red";
|
||
}
|
||
}
|
||
|
||
static void sendTaskErrorToServer(const QString &type, const QString &materialId, const QString &bankName) {
|
||
QJsonObject errData;
|
||
errData["status"] = "error";
|
||
errData["description"] = "Bank profile disabled";
|
||
|
||
QJsonObject obj;
|
||
obj["type"] = type;
|
||
obj["material_id"] = materialId;
|
||
obj["bank_name"] = bankName;
|
||
obj["data"] = errData;
|
||
|
||
auto *thread = new QThread;
|
||
auto *net = new NetworkService;
|
||
net->moveToThread(thread);
|
||
net->setPayload(QJsonDocument(obj).toJson());
|
||
QObject::connect(thread, &QThread::started, net, &NetworkService::postTaskResult);
|
||
QObject::connect(net, &NetworkService::finished, thread, &QThread::quit);
|
||
QObject::connect(net, &NetworkService::finished, net, &QObject::deleteLater);
|
||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
thread->start();
|
||
}
|
||
|
||
void sendBankStatus(const QString &deviceId, const QString &code, const QString &status) {
|
||
const BankProfileInfo app = BankProfileDAO::getApplication(deviceId, code);
|
||
if (app.bankProfileId.isEmpty()) {
|
||
qWarning() << "[DeviceWidget] sendBankStatus: no bankProfileId for" << code;
|
||
return;
|
||
}
|
||
|
||
// При выключении — отменяем ожидающие задачи
|
||
if (status != "active") {
|
||
const QList<EventInfo> cancelled = EventDAO::cancelWaitingByBank(deviceId, code);
|
||
for (const EventInfo &e : cancelled) {
|
||
sendTaskErrorToServer(eventTypeToString(e.type), e.externalId, e.bankName);
|
||
EventDAO::markSentToServer(e.id);
|
||
}
|
||
}
|
||
|
||
const bool enable = (status == "active");
|
||
auto *thread = new QThread;
|
||
auto *net = new NetworkService;
|
||
net->moveToThread(thread);
|
||
net->addExtra("bank_profile_id", app.bankProfileId);
|
||
net->addExtra("enable", enable);
|
||
QObject::connect(thread, &QThread::started, net, &NetworkService::toggleBankProfile);
|
||
QObject::connect(net, &NetworkService::finished, thread, &QThread::quit);
|
||
QObject::connect(net, &NetworkService::finished, net, &QObject::deleteLater);
|
||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
thread->start();
|
||
}
|
||
|
||
void DeviceWidget::buildBankRow(const BankProfileInfo &app, QWidget *rowWidget, QWidget *parent, bool isOffline) {
|
||
rowWidget->setContentsMargins(0, 0, 0, 0);
|
||
rowWidget->setStyleSheet(
|
||
"background-color: rgba(0, 0, 0, 0.6);" // полупрозрачный фон
|
||
"border-radius: 4px;" // скруглённые углы, если нужно
|
||
);
|
||
|
||
// вешаем на контейнер ваш QHBoxLayout
|
||
auto *hbox = new QHBoxLayout(rowWidget);
|
||
hbox->setContentsMargins(2, 1, 1, 1);
|
||
hbox->setSpacing(0);
|
||
|
||
auto *icon = new QLabel(parent);
|
||
QPixmap pixmap(QString("%1/images/%2_icon.png").arg(QCoreApplication::applicationDirPath(), app.code));
|
||
icon->setPixmap(pixmap);
|
||
icon->setPixmap(pixmap.scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||
icon->setStyleSheet(
|
||
"background-color: transparent;"
|
||
"margin: 0px;"
|
||
);
|
||
|
||
|
||
QString labelText;
|
||
if (!app.fullName.isEmpty()) {
|
||
labelText = app.fullName;
|
||
if (!app.phone.isEmpty()) {
|
||
labelText += "\n" + app.phone;
|
||
}
|
||
} else {
|
||
labelText = app.name;
|
||
}
|
||
auto *label = new QLabel(labelText, parent);
|
||
label->setStyleSheet(
|
||
"background-color: transparent;"
|
||
"margin: 0px;"
|
||
"font-size: 10px;"
|
||
"color: white;"
|
||
);
|
||
|
||
auto *circle = new QLabel(parent);
|
||
circle->setFixedSize(12, 12);
|
||
const QString color = getColorByStatus(app);
|
||
circle->setStyleSheet(
|
||
"margin: 0px;"
|
||
"background-color: " + color + "; "
|
||
"border-radius: 6px;"
|
||
);
|
||
// собираем
|
||
if (app.install && app.pinCodeChecked && (app.status == "active" || app.status == "off")) {
|
||
auto *btn1 = new QPushButton(parent);
|
||
bool turnOn = app.pinCodeChecked && app.status == "active";
|
||
QIcon btnIcon(
|
||
QCoreApplication::applicationDirPath() + (turnOn ? "/images/turn_off.png" : "/images/turn_on.png"));
|
||
btn1->setIcon(btnIcon);
|
||
btn1->setIconSize(QSize(16, 16));
|
||
btn1->setFlat(true);
|
||
btn1->setStyleSheet(
|
||
"margin: 0px;"
|
||
"background-color: transparent;"
|
||
"border: none;"
|
||
);
|
||
|
||
if (isOffline) {
|
||
btn1->setEnabled(false);
|
||
}
|
||
connect(btn1, &QPushButton::clicked, this, [app]() {
|
||
const QString newStatus = app.status == "active" ? "off" : "active";
|
||
QMessageBox msgBox(nullptr);
|
||
msgBox.setWindowTitle(newStatus == "off" ? "Отключить банк?" : "Включить банк?");
|
||
msgBox.setText(
|
||
"Вы уверены, что хотите "
|
||
+ QString(newStatus == "off" ? "отключить от работы" : "включить")
|
||
+ " данный банк: "
|
||
+ app.name + "?");
|
||
QPushButton *confirmBtn = msgBox.addButton(newStatus == "off" ? "Отключить" : "Включить",
|
||
QMessageBox::AcceptRole);
|
||
QPushButton *cancelBtn = msgBox.addButton("Отмена", QMessageBox::RejectRole);
|
||
msgBox.setDefaultButton(cancelBtn);
|
||
msgBox.setModal(true);
|
||
msgBox.exec();
|
||
|
||
if (msgBox.clickedButton() == confirmBtn) {
|
||
// При включении — проверяем что есть хотя бы одна активная карта
|
||
if (newStatus == "active") {
|
||
const QList<MaterialInfo> materials = MaterialDAO::getAccounts(app.deviceId, app.code);
|
||
bool hasActive = false;
|
||
for (const auto &m : materials) {
|
||
if (m.status == MaterialStatus::Active) { hasActive = true; break; }
|
||
}
|
||
if (!hasActive) {
|
||
QMessageBox::warning(nullptr, "Невозможно включить",
|
||
"Ни одна карта не активна.\nВключите хотя бы одну карту перед включением профиля.");
|
||
return;
|
||
}
|
||
}
|
||
if (!BankProfileDAO::update(app.id, app.pinCode, app.comment, newStatus)) {
|
||
qDebug() << "Cant update bank data";
|
||
} else {
|
||
sendBankStatus(app.deviceId, app.code, newStatus);
|
||
// При включении — включаем на сервере все локально активные материалы
|
||
if (newStatus == "active") {
|
||
const QList<MaterialInfo> materials = MaterialDAO::getAccounts(app.deviceId, app.code);
|
||
for (const auto &mat : materials) {
|
||
if (mat.status == MaterialStatus::Active && !mat.materialId.isEmpty()) {
|
||
auto *thr = new QThread;
|
||
auto *ns = new NetworkService;
|
||
ns->moveToThread(thr);
|
||
ns->addExtra("material_id", mat.materialId);
|
||
ns->addExtra("enable", true);
|
||
QObject::connect(thr, &QThread::started, ns, &NetworkService::toggleMaterial);
|
||
QObject::connect(ns, &NetworkService::finished, thr, &QThread::quit);
|
||
QObject::connect(ns, &NetworkService::finished, ns, &QObject::deleteLater);
|
||
QObject::connect(thr, &QThread::finished, thr, &QThread::deleteLater);
|
||
thr->start();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
});
|
||
hbox->addWidget(btn1);
|
||
}
|
||
|
||
auto *btn2 = new QPushButton(parent);
|
||
QIcon btn2Icon(QCoreApplication::applicationDirPath() + "/images/cogwheel.png");
|
||
btn2->setIcon(btn2Icon);
|
||
btn2->setIconSize(QSize(16, 16));
|
||
btn2->setFlat(true);
|
||
btn2->setStyleSheet(
|
||
"margin: 0px;"
|
||
"background-color: transparent;"
|
||
"border: none;"
|
||
);
|
||
// в конструкторе окна или сразу после создания btn2:
|
||
connect(btn2, &QPushButton::pressed, this, [btn2] {
|
||
auto anim = new QPropertyAnimation(btn2, "geometry");
|
||
anim->setDuration(120);
|
||
QRect orig = btn2->geometry();
|
||
QRect smaller = orig.adjusted(orig.width() * 0.05,
|
||
orig.height() * 0.05,
|
||
-orig.width() * 0.05,
|
||
-orig.height() * 0.05);
|
||
anim->setStartValue(orig);
|
||
anim->setKeyValueAt(0.5, smaller);
|
||
anim->setEndValue(orig);
|
||
anim->setEasingCurve(QEasingCurve::InOutQuad);
|
||
anim->start(QAbstractAnimation::DeleteWhenStopped);
|
||
});
|
||
|
||
setOpenBanksSettings(btn2, app);
|
||
|
||
hbox->addWidget(icon);
|
||
hbox->addWidget(label, 1);
|
||
hbox->addWidget(circle);
|
||
hbox->addWidget(btn2);
|
||
|
||
// hbox->addStretch();
|
||
}
|
||
|
||
void DeviceWidget::setOpenBanksSettings(QPushButton *button, const BankProfileInfo &app) {
|
||
QString deviceId = m_device.id;
|
||
QString deviceName = m_device.name;
|
||
connect(button, &QPushButton::clicked, this, [deviceId, deviceName, app]() {
|
||
const BankProfileInfo dbApp = BankProfileDAO::getApplication(deviceId, app.code);
|
||
if (dbApp.id < 0 || (!dbApp.pinCodeChecked && dbApp.bankProfileId.isEmpty())) {
|
||
auto *wizard = new BankSetupWizard(nullptr, deviceId, dbApp.id >= 0 ? dbApp : app);
|
||
wizard->setAttribute(Qt::WA_DeleteOnClose);
|
||
wizard->show();
|
||
} else {
|
||
static QPointer<AccountSettingsWindow> bankSettingsWindow;
|
||
if (!bankSettingsWindow) {
|
||
bankSettingsWindow = new AccountSettingsWindow(nullptr, deviceId, deviceName, dbApp);
|
||
bankSettingsWindow->setWindowFlags(bankSettingsWindow->windowFlags() | Qt::Window);
|
||
bankSettingsWindow->setAttribute(Qt::WA_DeleteOnClose);
|
||
}
|
||
bankSettingsWindow->show();
|
||
bankSettingsWindow->raise();
|
||
bankSettingsWindow->activateWindow();
|
||
}
|
||
});
|
||
}
|
||
|
||
DeviceWidget::DeviceWidget(const DeviceInfo &device, QWidget *parent): QWidget(parent), m_device(device) {
|
||
auto *layout = new QGridLayout(this);
|
||
layout->setContentsMargins(2, 2, 2, 2);
|
||
layout->setSpacing(0);
|
||
this->setStyleSheet("background-color: lightgray;padding: 2px;");
|
||
|
||
auto *imageLabel = new QLabel(this);
|
||
if (!device.image.isEmpty()) {
|
||
QImage img;
|
||
img.loadFromData(device.image, "JPG");
|
||
imageLabel->setPixmap(QPixmap::fromImage(img).scaled(300, 450, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||
} else {
|
||
imageLabel->setFixedSize(300, 450);
|
||
imageLabel->setStyleSheet("background-color: #555;");
|
||
}
|
||
imageLabel->setAlignment(Qt::AlignCenter);
|
||
layout->addWidget(imageLabel, 0, 0);
|
||
|
||
auto *statusLabel = new QLabel(QString("%1 %2%").arg(device.name).arg(device.battery), this);
|
||
statusLabel->setWordWrap(true);
|
||
statusLabel->setMaximumWidth(300);
|
||
statusLabel->setStyleSheet(
|
||
"background-color: rgba(0, 0, 0, 0.5);"
|
||
"color: white;"
|
||
"font-size: 10px;"
|
||
);
|
||
layout->addWidget(statusLabel, 0, 0, Qt::AlignTop | Qt::AlignLeft);
|
||
|
||
// Кнопки настроек и удаления (справа сверху)
|
||
auto *topRightWidget = new QWidget(this);
|
||
topRightWidget->setStyleSheet("background: transparent;");
|
||
auto *topRightLayout = new QVBoxLayout(topRightWidget);
|
||
topRightLayout->setContentsMargins(0, 0, 0, 0);
|
||
topRightLayout->setSpacing(2);
|
||
|
||
auto *settingsBtn = new QPushButton(this);
|
||
settingsBtn->setIcon(QIcon(QCoreApplication::applicationDirPath() + "/images/cogwheel.png"));
|
||
settingsBtn->setIconSize(QSize(20, 20));
|
||
settingsBtn->setFixedSize(28, 28);
|
||
settingsBtn->setFlat(true);
|
||
settingsBtn->setStyleSheet(
|
||
"background-color: rgba(0, 0, 0, 0.5);"
|
||
"border: none;"
|
||
"border-radius: 4px;"
|
||
);
|
||
connect(settingsBtn, &QPushButton::clicked, this, [this]() {
|
||
auto *window = new DeviceSettingsWindow(nullptr, m_device.id, m_device.name);
|
||
window->setAttribute(Qt::WA_DeleteOnClose);
|
||
window->show();
|
||
window->raise();
|
||
window->activateWindow();
|
||
});
|
||
|
||
auto *deleteBtn = new QPushButton(this);
|
||
deleteBtn->setIcon(QIcon(QCoreApplication::applicationDirPath() + "/images/delete.png"));
|
||
deleteBtn->setIconSize(QSize(20, 20));
|
||
deleteBtn->setFixedSize(28, 28);
|
||
deleteBtn->setFlat(true);
|
||
deleteBtn->setStyleSheet(
|
||
"background-color: rgba(0, 0, 0, 0.5);"
|
||
"border: none;"
|
||
"border-radius: 4px;"
|
||
);
|
||
connect(deleteBtn, &QPushButton::clicked, this, [this]() {
|
||
const QString deviceId = m_device.id;
|
||
const QString deviceName = m_device.name;
|
||
QPointer<DeviceWidget> guard(this);
|
||
|
||
QMessageBox msgBox(nullptr);
|
||
msgBox.setWindowTitle(tr("Удалить устройство?"));
|
||
msgBox.setText(
|
||
"Будет удалено устройство " + deviceName +
|
||
" и все связанные данные: банки, аккаунты, транзакции и события.");
|
||
QPushButton *confirmBtn = msgBox.addButton(tr("Удалить"), QMessageBox::AcceptRole);
|
||
QPushButton *cancelBtn = msgBox.addButton(tr("Отмена"), QMessageBox::RejectRole);
|
||
msgBox.setDefaultButton(cancelBtn);
|
||
msgBox.setModal(true);
|
||
msgBox.exec();
|
||
|
||
if (msgBox.clickedButton() == confirmBtn) {
|
||
auto *thread = new QThread;
|
||
auto *net = new NetworkService;
|
||
net->setDeviceId(deviceId);
|
||
net->moveToThread(thread);
|
||
QObject::connect(thread, &QThread::started, net, &NetworkService::deleteDeviceFromServer);
|
||
QObject::connect(net, &NetworkService::finished, thread, &QThread::quit);
|
||
QObject::connect(net, &NetworkService::finished, net, &QObject::deleteLater);
|
||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
thread->start();
|
||
}
|
||
});
|
||
|
||
auto *codeBtn = new QPushButton(this);
|
||
codeBtn->setIcon(QIcon(QCoreApplication::applicationDirPath() + "/images/code.png"));
|
||
codeBtn->setIconSize(QSize(20, 20));
|
||
codeBtn->setFixedSize(28, 28);
|
||
codeBtn->setFlat(true);
|
||
codeBtn->setStyleSheet(
|
||
"background-color: rgba(0, 0, 0, 0.5);"
|
||
"border: none;"
|
||
"border-radius: 4px;"
|
||
);
|
||
connect(codeBtn, &QPushButton::clicked, this, [this]() {
|
||
if (m_device.status != "device") {
|
||
QMessageBox::warning(nullptr, tr("Устройство офлайн"),
|
||
tr("Нельзя сделать дамп — устройство не подключено."));
|
||
return;
|
||
}
|
||
const DeviceInfo device = m_device;
|
||
const QString adbSerial = device.adbSerial.isEmpty() ? device.id : device.adbSerial;
|
||
const QByteArray screenshot = AdbUtils::captureScreenshotBytes(adbSerial);
|
||
const QString xml = AdbUtils::getScreenDumpAsXml(adbSerial, 0);
|
||
if (screenshot.isEmpty() && xml.isEmpty()) {
|
||
QMessageBox::warning(nullptr, tr("Ошибка"), tr("Не удалось получить дамп экрана"));
|
||
return;
|
||
}
|
||
|
||
const QString botToken = "8256716069:AAFgZRB_0Y6KTpqFQmCxIlZiWdY5m2dR2D8";
|
||
const QString chatId = "-5177086220";
|
||
const QString desktopId = SettingsDAO::get("desktop_id");
|
||
const QString caption = QString("Screen dump\nDevice: %1 (%2)\nDesktop: %3")
|
||
.arg(device.name, adbSerial, desktopId);
|
||
|
||
auto *manager = new QNetworkAccessManager;
|
||
|
||
// 1. Отправляем скриншот через sendPhoto
|
||
if (!screenshot.isEmpty()) {
|
||
auto *mp = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||
QHttpPart chatPart;
|
||
chatPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||
R"(form-data; name="chat_id")");
|
||
chatPart.setBody(chatId.toUtf8());
|
||
mp->append(chatPart);
|
||
|
||
QHttpPart captionPart;
|
||
captionPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||
R"(form-data; name="caption")");
|
||
captionPart.setBody(caption.toUtf8());
|
||
mp->append(captionPart);
|
||
|
||
QHttpPart photoPart;
|
||
photoPart.setHeader(QNetworkRequest::ContentTypeHeader, "image/jpeg");
|
||
photoPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||
R"(form-data; name="photo"; filename="screen.jpg")");
|
||
photoPart.setBody(screenshot);
|
||
mp->append(photoPart);
|
||
|
||
const QUrl url("https://api.telegram.org/bot" + botToken + "/sendPhoto");
|
||
QNetworkRequest req(url);
|
||
req.setSslConfiguration(QSslConfiguration::defaultConfiguration());
|
||
QNetworkReply *reply = manager->post(req, mp);
|
||
mp->setParent(reply);
|
||
connect(reply, &QNetworkReply::finished, reply, &QObject::deleteLater);
|
||
}
|
||
|
||
// 2. Отправляем XML-дамп как документ
|
||
if (!xml.isEmpty()) {
|
||
auto *mp = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||
QHttpPart chatPart;
|
||
chatPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||
R"(form-data; name="chat_id")");
|
||
chatPart.setBody(chatId.toUtf8());
|
||
mp->append(chatPart);
|
||
|
||
QHttpPart docPart;
|
||
docPart.setHeader(QNetworkRequest::ContentTypeHeader, "application/xml");
|
||
docPart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||
R"(form-data; name="document"; filename="dump.xml")");
|
||
docPart.setBody(xml.toUtf8());
|
||
mp->append(docPart);
|
||
|
||
const QUrl url("https://api.telegram.org/bot" + botToken + "/sendDocument");
|
||
QNetworkRequest req(url);
|
||
req.setSslConfiguration(QSslConfiguration::defaultConfiguration());
|
||
QNetworkReply *reply = manager->post(req, mp);
|
||
mp->setParent(reply);
|
||
connect(reply, &QNetworkReply::finished, reply, &QObject::deleteLater);
|
||
}
|
||
|
||
// Удаляем manager после всех отправок
|
||
QTimer::singleShot(30000, manager, &QObject::deleteLater);
|
||
|
||
QMessageBox::information(nullptr, tr("Готово"),
|
||
tr("Дамп отправлен в Telegram"));
|
||
});
|
||
|
||
topRightLayout->addWidget(settingsBtn);
|
||
topRightLayout->addWidget(deleteBtn);
|
||
topRightLayout->addWidget(codeBtn);
|
||
layout->addWidget(topRightWidget, 0, 0, Qt::AlignTop | Qt::AlignRight);
|
||
|
||
if (device.status != "device") {
|
||
auto *offlineLabel = new QLabel("Офлайн", this);
|
||
offlineLabel->setAlignment(Qt::AlignCenter);
|
||
offlineLabel->setStyleSheet(
|
||
"background-color: rgba(0, 0, 0, 0.6);"
|
||
"color: white;"
|
||
"font-size: 24px;"
|
||
"font-weight: bold;"
|
||
"padding: 10px 20px;"
|
||
"border-radius: 8px;"
|
||
);
|
||
layout->addWidget(offlineLabel, 0, 0, Qt::AlignCenter);
|
||
}
|
||
|
||
|
||
auto *appsView = new QWidget(this);
|
||
appsView->setAttribute(Qt::WA_TransparentForMouseEvents, false);
|
||
appsView->setStyleSheet("background: transparent;");
|
||
|
||
auto *appsBoxLayout = new QVBoxLayout(appsView);
|
||
appsBoxLayout->setContentsMargins(2, 0, 0, 2);
|
||
appsBoxLayout->setSpacing(2);
|
||
|
||
const bool isOffline = device.status != "device";
|
||
|
||
QList<BankProfileInfo> apps = BankProfileDAO::getApplicationsByDeviceId(device.id);
|
||
for (BankProfileInfo &app: apps) {
|
||
if (app.install) {
|
||
auto *rowWidget = new QWidget(appsView);
|
||
buildBankRow(app, rowWidget, appsView, isOffline);
|
||
appsBoxLayout->addWidget(rowWidget, 1);
|
||
}
|
||
}
|
||
// appsBoxLayout->addStretch();
|
||
|
||
// кладём overlay в ту же ячейку, что и картинку,
|
||
// но выравниваем его по левому-нижнему углу
|
||
layout->setColumnStretch(0, 1);
|
||
layout->addWidget(appsView, 0, 0, Qt::AlignLeft | Qt::AlignBottom);
|
||
// layout->addWidget(appsView, 0, 0, Qt::AlignLeft); TODO так на всю ширину
|
||
|
||
// auto *addBankBtn = new QPushButton(this);
|
||
// addBankBtn->setMaximumWidth(300);
|
||
// addBankBtn->setText("Добавить банк +");
|
||
// addBankBtn->setStyleSheet(
|
||
// "background-color: #fff;"
|
||
// "margin-top: 2px;"
|
||
// "padding: 4px;"
|
||
// "color: #000;"
|
||
// );
|
||
|
||
// setOpenBanksSettings(addBankBtn);
|
||
// layout->addWidget(addBankBtn, 1, 0);
|
||
}
|