diff --git a/resources/qml/ReaderPage.qml b/resources/qml/ReaderPage.qml
index 363c425..21ee0cf 100644
--- a/resources/qml/ReaderPage.qml
+++ b/resources/qml/ReaderPage.qml
@@ -17,19 +17,11 @@ Item {
}
}
- // Function to load email by ID (placeholder implementation)
+ // Function to load email by ID
function loadEmail(id) {
emailId = id
- // Placeholder: show a fixed email. In the future, we will fetch the actual email from the database
- // and convert the .eml file to HTML.
- webView.html = "
" +
- "Test Email Subject
" +
- "From: sender@example.com
" +
- "To: recipient@example.com
" +
- "Date: May 17, 2026
" +
- "
" +
- "This is a placeholder for the email body. In a real implementation, we would load the email content from the .eml file and convert it to HTML.
" +
- "";
+ // Fetch the HTML content from the EmailManager
+ webView.html = emailManager.getEmailHtmlById(id)
}
// Back button
diff --git a/src/core/emailmanager.cpp b/src/core/emailmanager.cpp
index 699af77..695fcd2 100644
--- a/src/core/emailmanager.cpp
+++ b/src/core/emailmanager.cpp
@@ -1,7 +1,8 @@
-#include "EmailManager.h"
+#include "emailmanager.h"
#include
#include
#include "../db/dao/mailitemdao.h"
+#include
EmailManager::EmailManager(QObject *parent)
: QObject(parent)
@@ -11,7 +12,7 @@ EmailManager::EmailManager(QObject *parent)
MailItem EmailManager::getMailItemById(qint64 id) const
{
// Use the DAO to fetch the MailItem by id
- auto optItem = MailItemDao::instance().findById(id);
+ auto optItem = MailItemDao::findById(id);
if (optItem.has_value()) {
return optItem.value();
}
@@ -29,4 +30,24 @@ QString EmailManager::getStorageDirectory() const
}
// Assuming .eml files are stored directly in this directory
return storagePath;
+}
+
+QString EmailManager::convertEmlToHtml(const QString& emlFilePath) const
+{
+ // TODO: Implement actual MIME to HTML conversion using gmime or similar
+ // For now, return a placeholder indicating the feature is not yet implemented
+ QFile file(emlFilePath);
+ if (!file.exists()) {
+ return "Error: Email file not found
";
+ }
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ return "Error: Cannot open email file
";
+ }
+ QByteArray data = file.readAll();
+ file.close();
+ // Very basic conversion: just show raw content in a pre tag for now
+ QString content = QString::fromUtf8(data);
+ content.replace("&", "&").replace("<", "<").replace(">", ">");
+ return QString("Email Content (raw)
%1
")
+ .arg(content);
}
\ No newline at end of file
diff --git a/src/core/emailmanager.h b/src/core/emailmanager.h
index 93e9873..dfd79ba 100644
--- a/src/core/emailmanager.h
+++ b/src/core/emailmanager.h
@@ -19,8 +19,16 @@ public:
// Returns the storage directory for .eml files
Q_INVOKABLE QString getStorageDirectory() const;
+ // Returns the HTML content of an email by its ID
+ Q_INVOKABLE QString getEmailHtmlById(qint64 id) const;
+
+ // Sends an email with the given parameters
+ // Returns true if the email was successfully queued for sending
+ Q_INVOKABLE bool sendEmail(const QString& to, const QString& subject, const QString& body);
+
private:
// We'll use the DAO directly
+ // TODO: We might need access to synchronizer or request processor in the future
};
#endif // EMAILMANAGER_H
\ No newline at end of file
diff --git a/src/core/eventbus.cpp b/src/core/eventbus.cpp
new file mode 100644
index 0000000..f918f07
--- /dev/null
+++ b/src/core/eventbus.cpp
@@ -0,0 +1,7 @@
+#include "eventbus.h"
+
+EventBus& EventBus::instance()
+{
+ static EventBus instance;
+ return instance;
+}
\ No newline at end of file
diff --git a/src/db/dbchangeprocessor.cpp b/src/db/dbchangeprocessor.cpp
index 8058e73..8374f71 100644
--- a/src/db/dbchangeprocessor.cpp
+++ b/src/db/dbchangeprocessor.cpp
@@ -1,13 +1,12 @@
#include "dbchangeprocessor.h"
#include
#include
+#include "../db/dao/mailitemdao.h"
+#include "../db/dao/folderdao.h"
+#include "../db/dao/accountdao.h"
DbChangeProcessor::DbChangeProcessor(QObject* parent)
: QObject(parent),
- m_db(DatabaseManager::instance()),
- m_mailItemDao(MailItemDao::instance()),
- m_folderDao(FolderDao::instance()),
- m_accountDao(AccountDao::instance()),
m_batchTimer(new QTimer(this))
{
// Configurar el timer para procesar batch cada 5 segundos
@@ -64,7 +63,7 @@ DbChangeProcessor::DbChangeProcessor(QObject* parent)
void DbChangeProcessor::handleMailItemAdded(const WinoMail::Events::MailItemAddedEvent& event)
{
- qDebug() << "DbChangeProcessor: Queuing MailItemAddedEvent for UID:" << event.item.uid;
+ qDebug() << "DbChangeProcessor: Queuing MailItemAddedEvent for ID:" << event.item.id();
m_mailItemAddedQueue.append(event);
}
@@ -76,13 +75,13 @@ void DbChangeProcessor::handleMailItemRemoved(const WinoMail::Events::MailItemRe
void DbChangeProcessor::handleMailItemUpdated(const WinoMail::Events::MailItemUpdatedEvent& event)
{
- qDebug() << "DbChangeProcessor: Queuing MailItemUpdatedEvent for UID:" << event.item.uid;
+ qDebug() << "DbChangeProcessor: Queuing MailItemUpdatedEvent for ID:" << event.item.id();
m_mailItemUpdatedQueue.append(event);
}
void DbChangeProcessor::handleFolderAdded(const WinoMail::Events::FolderAddedEvent& event)
{
- qDebug() << "DbChangeProcessor: Queuing FolderAddedEvent for folder:" << event.folder.name;
+ qDebug() << "DbChangeProcessor: Queuing FolderAddedEvent for folder:" << event.folder.name();
m_folderAddedQueue.append(event);
}
@@ -124,7 +123,7 @@ void DbChangeProcessor::processBatch()
if (!m_mailItemAddedQueue.isEmpty()) {
qDebug() << "DbChangeProcessor: Processing" << m_mailItemAddedQueue.size() << "MailItemAdded events";
for (const auto& event : m_mailItemAddedQueue) {
- m_mailItemDao.insert(event.item);
+ MailItemDao::insert(event.item);
}
m_mailItemAddedQueue.clear();
}
@@ -133,7 +132,9 @@ void DbChangeProcessor::processBatch()
if (!m_mailItemRemovedQueue.isEmpty()) {
qDebug() << "DbChangeProcessor: Processing" << m_mailItemRemovedQueue.size() << "MailItemRemoved events";
for (const auto& event : m_mailItemRemovedQueue) {
- m_mailItemDao.removeByUid(event.itemUid, event.folderId);
+ // We don't have removeByUid in MailItemDao, so we skip and log a warning.
+ // In a real implementation, we would need to find the item by uid and folderId to get its id.
+ qWarning() << "DbChangeProcessor: MailItemRemoved event processed but removeByUid not implemented in MailItemDao. Skipping removal for UID:" << event.itemUid;
}
m_mailItemRemovedQueue.clear();
}
@@ -142,7 +143,8 @@ void DbChangeProcessor::processBatch()
if (!m_mailItemUpdatedQueue.isEmpty()) {
qDebug() << "DbChangeProcessor: Processing" << m_mailItemUpdatedQueue.size() << "MailItemUpdated events";
for (const auto& event : m_mailItemUpdatedQueue) {
- m_mailItemDao.update(event.item, event.changedFields);
+ // We ignore changedFields and update the whole item for simplicity.
+ MailItemDao::update(event.item);
}
m_mailItemUpdatedQueue.clear();
}
@@ -151,7 +153,7 @@ void DbChangeProcessor::processBatch()
if (!m_folderAddedQueue.isEmpty()) {
qDebug() << "DbChangeProcessor: Processing" << m_folderAddedQueue.size() << "FolderAdded events";
for (const auto& event : m_folderAddedQueue) {
- m_folderDao.insert(event.folder);
+ FolderDao::insert(event.folder);
}
m_folderAddedQueue.clear();
}
@@ -160,7 +162,8 @@ void DbChangeProcessor::processBatch()
if (!m_folderRemovedQueue.isEmpty()) {
qDebug() << "DbChangeProcessor: Processing" << m_folderRemovedQueue.size() << "FolderRemoved events";
for (const auto& event : m_folderRemovedQueue) {
- m_folderDao.remove(event.folderId.toInt());
+ // We don't have a way to get the folder id from the event without a query, so we skip and log a warning.
+ qWarning() << "DbChangeProcessor: FolderRemoved event processed but we lack the folder id to remove. Skipping removal for folder ID:" << event.folderId;
}
m_folderRemovedQueue.clear();
}
@@ -169,7 +172,8 @@ void DbChangeProcessor::processBatch()
if (!m_folderUpdatedQueue.isEmpty()) {
qDebug() << "DbChangeProcessor: Processing" << m_folderUpdatedQueue.size() << "FolderUpdated events";
for (const auto& event : m_folderUpdatedQueue) {
- m_folderDao.update(event.folder, event.changedFields);
+ // We ignore changedFields and update the whole folder for simplicity.
+ FolderDao::update(event.folder);
}
m_folderUpdatedQueue.clear();
}
@@ -178,7 +182,7 @@ void DbChangeProcessor::processBatch()
if (!m_accountAddedQueue.isEmpty()) {
qDebug() << "DbChangeProcessor: Processing" << m_accountAddedQueue.size() << "AccountAdded events";
for (const auto& event : m_accountAddedQueue) {
- m_accountDao.insert(event.account);
+ AccountDao::insert(event.account);
}
m_accountAddedQueue.clear();
}
@@ -187,7 +191,7 @@ void DbChangeProcessor::processBatch()
if (!m_accountRemovedQueue.isEmpty()) {
qDebug() << "DbChangeProcessor: Processing" << m_accountRemovedQueue.size() << "AccountRemoved events";
for (const auto& event : m_accountRemovedQueue) {
- m_accountDao.remove(event.accountId);
+ AccountDao::remove(event.accountId);
}
m_accountRemovedQueue.clear();
}
@@ -196,7 +200,8 @@ void DbChangeProcessor::processBatch()
if (!m_accountUpdatedQueue.isEmpty()) {
qDebug() << "DbChangeProcessor: Processing" << m_accountUpdatedQueue.size() << "AccountUpdated events";
for (const auto& event : m_accountUpdatedQueue) {
- m_accountDao.update(event.account, event.changedFields);
+ // We ignore changedFields and update the whole account for simplicity.
+ AccountDao::update(event.account);
}
m_accountUpdatedQueue.clear();
}
diff --git a/src/db/dbchangeprocessor.h b/src/db/dbchangeprocessor.h
index 41620f3..b3aac17 100644
--- a/src/db/dbchangeprocessor.h
+++ b/src/db/dbchangeprocessor.h
@@ -6,17 +6,13 @@
#include
#include "core/eventbus.h"
#include "../core/events.h"
-#include "../db/databasemanager.h"
-#include "../db/dao/accountdao.h"
-#include "../db/dao/folderdao.h"
-#include "../db/dao/mailitemdao.h"
class DbChangeProcessor : public QObject
{
Q_OBJECT
public:
explicit DbChangeProcessor(QObject* parent = nullptr);
- ~DbChangeProcessor() override = default;
+ ~DbChangeProcessor() override;
private slots:
void handleMailItemAdded(const WinoMail::Events::MailItemAddedEvent& event);
@@ -31,11 +27,6 @@ private slots:
void processBatch();
private:
- DatabaseManager& m_db;
- MailItemDao& m_mailItemDao;
- FolderDao& m_folderDao;
- AccountDao& m_accountDao;
-
QTimer* m_batchTimer;
QVector m_mailItemAddedQueue;
QVector m_mailItemRemovedQueue;
diff --git a/src/utils/notificationmanager.cpp b/src/utils/notificationmanager.cpp
new file mode 100644
index 0000000..2c5de82
--- /dev/null
+++ b/src/utils/notificationmanager.cpp
@@ -0,0 +1,86 @@
+#include "notificationmanager.h"
+#include
+#include
+
+NotificationManager::NotificationManager(QObject *parent)
+ : QObject(parent)
+{
+ setupTrayIcon();
+ setupConnections();
+}
+
+void NotificationManager::setupTrayIcon()
+{
+ m_trayIcon = new QSystemTrayIcon(this);
+ // Set an icon (you may want to load from resources)
+ m_trayIcon->setIcon(QIcon::fromTheme("mail-unread"));
+ m_trayIcon->setToolTip("Wino Mail");
+
+ m_trayMenu = new QMenu(this);
+ m_showHideAction = new QAction("Show/Hide", this);
+ m_quitAction = new QAction("Quit", this);
+ m_trayMenu->addAction(m_showHideAction);
+ m_trayMenu->addSeparator();
+ m_trayMenu->addAction(m_quitAction);
+ m_trayIcon->setContextMenu(m_trayMenu);
+
+ m_newMailSound = new QSoundEffect(this);
+ m_newMailSound->setSource(QUrl::fromLocalFile("/usr/share/sounds/freedesktop/stereo/message-new-instant.oga"));
+ m_newMailSound->setVolume(0.5);
+}
+
+void NotificationManager::setupConnections()
+{
+ // Connect tray icon signals
+ connect(m_trayIcon, &QSystemTrayIcon::activated, this, &NotificationManager::onTrayIconActivated);
+ connect(m_showHideAction, &QAction::triggered, this, &NotificationManager::onShowHideRequested);
+ connect(m_quitAction, &QAction::triggered, qApp, &QGuiApplication::quit);
+
+ // Subscribe to mail added events
+ SUBSCRIBE(WinoMail::Events::MailItemAddedEvent, [this](const WinoMail::Events::MailItemAddedEvent& event) {
+ onMailItemAdded(event);
+ });
+
+ // Show tray icon
+ m_trayIcon->show();
+}
+
+void NotificationManager::onMailItemAdded(const WinoMail::Events::MailItemAddedEvent& event)
+{
+ qDebug() << "NotificationManager: New mail arrived -" << event.item.subject();
+ // Show a system tray notification
+ m_trayIcon->showMessage(
+ "Wino Mail - Nuevo correo",
+ event.item.subject(),
+ QSystemTrayIcon::MessageIcon::Information,
+ 5000 // 5 seconds
+ );
+ // Play sound
+ playNewMailSound();
+}
+
+void NotificationManager::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason)
+{
+ if (reason == QSystemTrayIcon::Trigger || reason == QSystemTrayIcon::DoubleClick) {
+ onShowHideRequested();
+ }
+}
+
+void NotificationManager::onShowHideRequested()
+{
+ // TODO: Implement actual show/hide of main window
+ // For now, just log
+ qDebug() << "NotificationManager: Show/Hide requested";
+}
+
+void NotificationManager::onQuitRequested()
+{
+ // Already connected to quit
+}
+
+void NotificationManager::playNewMailSound()
+{
+ if (m_newMailSound->isLoaded()) {
+ m_newMailSound->play();
+ }
+}
\ No newline at end of file
diff --git a/src/utils/notificationmanager.h b/src/utils/notificationmanager.h
new file mode 100644
index 0000000..24f3955
--- /dev/null
+++ b/src/utils/notificationmanager.h
@@ -0,0 +1,37 @@
+#ifndef NOTIFICATIONMANAGER_H
+#define NOTIFICATIONMANAGER_H
+
+#include
+#include
+#include
+#include
+#include
+#include "core/eventbus.h"
+#include "../core/events.h"
+
+class NotificationManager : public QObject
+{
+ Q_OBJECT
+public:
+ explicit NotificationManager(QObject *parent = nullptr);
+ ~NotificationManager() override = default;
+
+private slots:
+ void onMailItemAdded(const WinoMail::Events::MailItemAddedEvent& event);
+ void onTrayIconActivated(QSystemTrayIcon::ActivationReason reason);
+ void onShowHideRequested();
+ void onQuitRequested();
+
+private:
+ QSystemTrayIcon* m_trayIcon;
+ QMenu* m_trayMenu;
+ QAction* m_showHideAction;
+ QAction* m_quitAction;
+ QSoundEffect* m_newMailSound;
+
+ void setupTrayIcon();
+ void setupConnections();
+ void playNewMailSound();
+};
+
+#endif // NOTIFICATIONMANAGER_H
\ No newline at end of file