diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 5350c93..4ce2fea 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -115,11 +115,29 @@ MainWindow::MainWindow(QWidget *parent) connect(m_authManager, &AuthManager::signedOut, m_authDialog, &AuthDialog::reset); connect(m_authManager, &AuthManager::signedOut, m_authDialog, &AuthDialog::show); connect(m_authManager, &AuthManager::signedIn, this, [this]() { + m_store->setCurrentUserEmail(m_authManager->sessionData()->email); m_store->loadStartupData(); }); connect(m_store, &Store::startupDataLoaded, this, [this]() { ui->topLevelParticlesView->expandAll(); }); + connect(m_store, &Store::particleUpdated, this, [this](const QString &, const QString &particleId) { + if (particleId == m_selectedParticleId) + { + const Particle *particle = m_store->particleById(particleId); + if (particle && !particle->ackedByEmails.empty()) + { + QStringList acked; + for (const auto &email : particle->ackedByEmails) + acked.append(email); + ui->label_3->setText("Acked by: " + acked.join(", ")); + } + else + { + ui->label_3->setText(""); + } + } + }); // DocumentSend toolbar button opens text input dialog connect(ui->toolButton_3, &QToolButton::clicked, this, &MainWindow::showTextInputDialog); @@ -329,6 +347,7 @@ void MainWindow::onParticleSelectionChanged(const QItemSelection &selected, cons { ui->label->setText(""); ui->label_2->setText(""); + ui->label_3->setText(""); m_selectedParticleId.clear(); m_selectedParticleRow = -1; updateStatusBar(); @@ -352,6 +371,19 @@ void MainWindow::onParticleSelectionChanged(const QItemSelection &selected, cons ui->label->setText(""); } + // Show ack info + if (!particle->ackedByEmails.empty()) + { + QStringList acked; + for (const auto &email : particle->ackedByEmails) + acked.append(email); + ui->label_3->setText("Acked by: " + acked.join(", ")); + } + else + { + ui->label_3->setText(""); + } + // Mark seen on selection if (!particle->seen) { diff --git a/src/store.cpp b/src/store.cpp index 1150597..ca50496 100644 --- a/src/store.cpp +++ b/src/store.cpp @@ -791,8 +791,29 @@ Operation *Store::markParticlesSeen(const QStringList &particleIds) return new Operation(reply, this); } +void Store::setCurrentUserEmail(const QString &email) { m_currentUserEmail = email; } + Operation *Store::ackParticle(const QString &particleId) { + // Optimistic local update + for (auto it = m_particles.begin(); it != m_particles.end(); ++it) + { + for (int i = 0; i < it.value().size(); ++i) + { + if (it.value()[i].id == particleId) + { + auto &emails = it.value()[i].ackedByEmails; + if (!m_currentUserEmail.isEmpty() && + std::find(emails.begin(), emails.end(), m_currentUserEmail) == emails.end()) + { + emails.push_back(m_currentUserEmail); + emit particleUpdated(it.key(), particleId); + } + break; + } + } + } + QNetworkReply *reply = NetworkManager::instance().post( QString("/particles/%1/ack").arg(particleId), QJsonDocument()); return new Operation(reply, this); diff --git a/src/store.h b/src/store.h index 7c74128..e3ab598 100644 --- a/src/store.h +++ b/src/store.h @@ -85,6 +85,8 @@ public: Operation *markParticlesSeen(const QStringList &particleIds); Operation *ackParticle(const QString &particleId); + void setCurrentUserEmail(const QString &email); + signals: // ── Data-change signals ── @@ -106,6 +108,7 @@ private: QMap> m_particles; // streamId -> particles QMap m_networkIndex; // networkId -> index in m_networks QMap m_streamToNetwork; // streamId -> networkId + QString m_currentUserEmail; // ── JSON parsing ──