1
0
forked from BRT/arc
arc/views/device/DeviceWidget.cpp
slava b395ed41a5 Add bank profile toggling in DeviceWidget and enhance error handling in EventHandler
- Implemented `sendBankStatus` logic with `NetworkService` and threading for bank profile enable/disable functionality.
- Improved error handling in `EventHandler` by logging and updating events when bank profiles are disabled.
2026-03-25 16:05:49 +07:00

339 lines
13 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 "DeviceWidget.h"
#include <QVBoxLayout>
#include <QLabel>
#include <QPixmap>
#include <QImage>
#include <QPushButton>
#include <QCoreApplication>
#include <QPointer>
#include <QPropertyAnimation>
#include <QGraphicsScene>
#include <QMessageBox>
#include "bank/AccountSettingsWindow.h"
#include "bank/BankSettingsWindow.h"
#include "DeviceSettingsWindow.h"
#include "dao/ApplicationDAO.h"
#include "dao/DeviceDAO.h"
#include "db/ApplicationInfo.h"
#include "net/NetworkService.h"
#include <QThread>
QString getColorByStatus(const ApplicationInfo &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";
}
}
void sendBankStatus(const QString &deviceId, const QString &code, const QString &status) {
const ApplicationInfo app = ApplicationDAO::getApplication(deviceId, code);
if (app.bankProfileId.isEmpty()) {
qWarning() << "[DeviceWidget] sendBankStatus: no bankProfileId for" << code;
return;
}
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 ApplicationInfo &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;"
);
auto *label = new QLabel(app.name, 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 (!ApplicationDAO::update(app.id, app.pinCode, app.comment, newStatus)) {
qDebug() << "Cant update bank data";
} else {
sendBankStatus(app.deviceId, app.code, newStatus);
}
}
});
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 ApplicationInfo &app) {
QString deviceId = m_device.id;
QString deviceName = m_device.name;
connect(button, &QPushButton::clicked, this, [deviceId, deviceName, app]() {
static QPointer<AccountSettingsWindow> bankSettingsWindow;
// Если окна нет (либо ещё не было создано, либо уже удалилось) — создаём заново
if (!bankSettingsWindow) {
bankSettingsWindow = new AccountSettingsWindow(nullptr, deviceId, deviceName, app);
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;"
);
layout->addWidget(statusLabel, 0, 0, Qt::AlignTop | Qt::AlignLeft);
// Кнопки настроек и удаления (справа сверху)
auto *topRightWidget = new QWidget(this);
topRightWidget->setStyleSheet("background: transparent;");
auto *topRightLayout = new QHBoxLayout(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) {
DeviceDAO::deleteDevice(deviceId);
}
});
topRightLayout->addWidget(settingsBtn);
topRightLayout->addWidget(deleteBtn);
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<ApplicationInfo> apps = ApplicationDAO::getApplicationsByDeviceId(device.id);
for (ApplicationInfo &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);
}