#include "spacetray.h" #include "themes/lock.h" #include #include #include #include #include #include #include #include SpaceTray::SpaceTray(const QString &url, QObject *parent) : QObject(parent), m_statusUrl(url), m_doorOpen(false), m_oldDoorOpen(false), m_doorLastChange(0), m_spaceName("Unknown Space"), m_firstRun(true) { // Initialize icons from raw data QImage imgOpen(icon_open_data, 52, 48, 208, QImage::Format_RGBA8888); m_iconOpen = QIcon(QPixmap::fromImage(imgOpen)); QImage imgClosed(icon_closed_data, 52, 48, 208, QImage::Format_RGBA8888); m_iconClosed = QIcon(QPixmap::fromImage(imgClosed)); // Setup tray icon m_trayIcon = new QSystemTrayIcon(this); m_trayIcon->setIcon(m_iconClosed); m_trayIcon->setVisible(true); // Setup tray menu m_trayMenu = new QMenu(); QAction *quitAction = m_trayMenu->addAction("Quit"); connect(quitAction, &QAction::triggered, this, &SpaceTray::quit); m_trayIcon->setContextMenu(m_trayMenu); connect(m_trayIcon, &QSystemTrayIcon::activated, [this](QSystemTrayIcon::ActivationReason reason) { if (reason == QSystemTrayIcon::Trigger) { fetchData(); } }); // Setup network manager m_networkManager = new QNetworkAccessManager(this); // Setup timer (300 seconds as per previous delay=300 in C code) m_timer = new QTimer(this); connect(m_timer, &QTimer::timeout, this, &SpaceTray::fetchData); m_timer->start(300000); // 300 seconds in ms // Initial fetch fetchData(); } SpaceTray::~SpaceTray() { delete m_trayMenu; } void SpaceTray::fetchData() { QNetworkRequest request(m_statusUrl); request.setHeader(QNetworkRequest::UserAgentHeader, "Spacetray/0.42 (Qt)"); request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); QNetworkReply *reply = m_networkManager->get(request); connect(reply, &QNetworkReply::finished, this, [this, reply]() { onFinished(reply); }); } void SpaceTray::onFinished(QNetworkReply *reply) { if (reply->error() != QNetworkReply::NoError) { qWarning() << "Network error:" << reply->errorString(); reply->deleteLater(); return; } QByteArray data = reply->readAll(); reply->deleteLater(); // Remove UTF-8 BOM if present if (data.startsWith("\xEF\xBB\xBF")) { data.remove(0, 3); } QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson(data, &error); if (doc.isNull()) { qWarning() << "Failed to parse JSON:" << error.errorString(); qWarning() << "Raw data:" << data; return; } QJsonObject obj = doc.object(); m_spaceName = obj.value("space").toString("Unknown Space"); QJsonObject stateObj = obj.value("state").toObject(); m_oldDoorOpen = m_doorOpen; m_doorOpen = stateObj.value("open").toBool(); m_doorLastChange = stateObj.value("lastchange").toVariant().toLongLong(); updateTray(); if (!m_firstRun && m_doorOpen != m_oldDoorOpen) { QString dateStr = QDateTime::fromSecsSinceEpoch(m_doorLastChange).toString("yyyy-MM-dd HH:mm:ss"); QString status = m_doorOpen ? "open" : "closed"; showNotification(QString("%1: Door %2 since %3").arg(m_spaceName, status, dateStr)); } m_firstRun = false; } void SpaceTray::updateTray() { m_trayIcon->setIcon(m_doorOpen ? m_iconOpen : m_iconClosed); QString dateStr = QDateTime::fromSecsSinceEpoch(m_doorLastChange).toString("yyyy-MM-dd HH:mm:ss"); QString status = m_doorOpen ? "open" : "closed"; QString tooltip = QString("%1: Door %2 since %3").arg(m_spaceName, status, dateStr); m_trayIcon->setToolTip(tooltip); } void SpaceTray::showNotification(const QString &message) { m_trayIcon->showMessage("SpaceAPI widget for UNIX", message, m_doorOpen ? m_iconOpen : m_iconClosed); } void SpaceTray::quit() { QCoreApplication::quit(); }