Implement basic UI with QML (MailListPage) and batching DbChangeProcessor (Step 3-4 of transition plan)
This commit is contained in:
+9
-2
@@ -17,10 +17,9 @@ include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||
|
||||
# Resources
|
||||
qt6_add_resources(WinoMailQtResources
|
||||
PREFIX
|
||||
/
|
||||
FILES
|
||||
resources/qml/main.qml
|
||||
resources/qml/Shell.qml
|
||||
)
|
||||
|
||||
# Source files
|
||||
@@ -32,10 +31,18 @@ set(SRC_FILES
|
||||
src/core/models/folder.cpp
|
||||
src/services/synchronizer.cpp
|
||||
src/services/imap/imapsynchronizer.cpp
|
||||
src/services/outlook/outlooksynchronizer.cpp
|
||||
src/services/gmail/gmailsynchronizer.cpp
|
||||
src/services/request.cpp
|
||||
src/services/concreterequests.cpp
|
||||
src/services/requestprocessor.cpp
|
||||
src/services/changetype.cpp
|
||||
src/services/changprocessor.cpp
|
||||
src/db/databasemanager.cpp
|
||||
src/db/dao/accountdao.cpp
|
||||
src/db/dao/folderdao.cpp
|
||||
src/db/dao/mailitemdao.cpp
|
||||
src/db/dbchangeprocessor.cpp
|
||||
)
|
||||
|
||||
# Executable
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>resources/qml/main.qml</file>
|
||||
<file>resources/qml/Shell.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
@@ -0,0 +1,136 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
Item {
|
||||
id: mailListPage
|
||||
anchors.fill: parent
|
||||
|
||||
// Layout: SplitView for resizable panes
|
||||
SplitView {
|
||||
anchors.fill: parent
|
||||
|
||||
// Left pane: Folder list
|
||||
Rectangle {
|
||||
width: 200
|
||||
color: "#fafafa"
|
||||
ListView {
|
||||
id: folderListView
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
model: FolderModel {}
|
||||
delegate: Item {
|
||||
height: 40
|
||||
Layout.fillWidth: true
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: ListView.isCurrentItem ? "#e3f2fd" : "transparent"
|
||||
Text {
|
||||
text: folderName
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pointSize: 14
|
||||
color: ListView.isCurrentItem ? "#1976d2" : "#666"
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
folderListView.currentIndex = index
|
||||
// TODO: Load emails for selected folder
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Right pane: Email list and preview
|
||||
Rectangle {
|
||||
color: "#fafafa"
|
||||
SplitView {
|
||||
orientation: Qt.Vertical
|
||||
anchors.fill: parent
|
||||
|
||||
// Email list (top)
|
||||
Rectangle {
|
||||
Layout.minimumHeight: 200
|
||||
color: "#fafafa"
|
||||
ListView {
|
||||
id: emailListView
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
model: EmailModel {}
|
||||
delegate: Item {
|
||||
height: 60
|
||||
Layout.fillWidth: true
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: ListView.isCurrentItem ? "#e3f2fd" : "transparent"
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
// Sender avatar/initial
|
||||
Rectangle {
|
||||
width: 40
|
||||
height: 40
|
||||
color: "#cccccc"
|
||||
Text {
|
||||
text: senderInitial
|
||||
anchors.centerIn: parent
|
||||
font.pointSize: 16
|
||||
color: "#666"
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 4
|
||||
Text {
|
||||
text: senderName
|
||||
font.pointSize: 14
|
||||
color: "#333"
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
text: subject
|
||||
font.pointSize: 13
|
||||
color: "#666"
|
||||
elide: Text.ElideRight
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
text: time
|
||||
font.pointSize: 12
|
||||
color: "#999"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
emailListView.currentIndex = index
|
||||
// TODO: Show email preview in the bottom pane
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Email preview (bottom)
|
||||
Rectangle {
|
||||
Layout.minimumHeight: 200
|
||||
color: "#ffffff"
|
||||
Text {
|
||||
id: emailPreview
|
||||
text: "Select an email to preview"
|
||||
anchors.centerIn: parent
|
||||
font.pointSize: 14
|
||||
color: "#666"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Window 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
ApplicationWindow {
|
||||
id: shell
|
||||
visible: true
|
||||
width: 1024
|
||||
height: 768
|
||||
title: qsTr("Wino Mail Qt")
|
||||
|
||||
// Set the title from translator in Component.onCompleted
|
||||
Component.onCompleted: {
|
||||
title = translator.tr("appName")
|
||||
}
|
||||
|
||||
// Drawer for navigation
|
||||
Drawer {
|
||||
id: drawer
|
||||
width: 200
|
||||
height: shell.height
|
||||
Container {
|
||||
anchors.fill: parent
|
||||
Layout.alignment: Qt.AlignTop
|
||||
ScrollView {
|
||||
anchors.fill: parent
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
// App logo/name
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 60
|
||||
color: "#1976D2"
|
||||
Text {
|
||||
text: qsTr("Wino Mail")
|
||||
color: "white"
|
||||
font.pointSize: 18
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
// Navigation items
|
||||
NavigationItem {
|
||||
text: qsTr("Mail")
|
||||
icon: "mail"
|
||||
isChecked: stackView.currentIndex === 0
|
||||
onClicked: {
|
||||
drawer.close()
|
||||
stackView.currentIndex = 0
|
||||
}
|
||||
}
|
||||
NavigationItem {
|
||||
text: qsTr("Calendar")
|
||||
icon: "calendar"
|
||||
isChecked: stackView.currentIndex === 1
|
||||
onClicked: {
|
||||
drawer.close()
|
||||
stackView.currentIndex = 1
|
||||
}
|
||||
}
|
||||
NavigationItem {
|
||||
text: qsTr("Contacts")
|
||||
icon: "contacts"
|
||||
isChecked: stackView.currentIndex === 2
|
||||
onClicked: {
|
||||
drawer.close()
|
||||
stackView.currentIndex = 2
|
||||
}
|
||||
}
|
||||
NavigationItem {
|
||||
text: qsTr("Settings")
|
||||
icon: "settings"
|
||||
isChecked: stackView.currentIndex === 3
|
||||
onClicked: {
|
||||
drawer.close()
|
||||
stackView.currentIndex = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main content area with StackView for pages
|
||||
StackView {
|
||||
id: stackView
|
||||
anchors.fill: parent
|
||||
initialItem: mailListPage
|
||||
}
|
||||
|
||||
// Define pages
|
||||
MailListPage {
|
||||
id: mailListPage
|
||||
}
|
||||
// Placeholder for other pages
|
||||
Rectangle {
|
||||
color: "#f0f0f0"
|
||||
Text {
|
||||
text: qsTr("Calendar Page")
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
color: "#f0f0f0"
|
||||
Text {
|
||||
text: qsTr("Contacts Page")
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
color: "#f0f0f0"
|
||||
Text {
|
||||
text: qsTr("Settings Page")
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
// Hamburger button to open drawer
|
||||
MenuButton {
|
||||
icon: "menu"
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.margins: 10
|
||||
onClicked: drawer.open()
|
||||
}
|
||||
}
|
||||
|
||||
// Helper components
|
||||
component NavigationItem: Button {
|
||||
Layout.fillWidth: true
|
||||
height: 48
|
||||
padding: 0
|
||||
contentItem: RowLayout {
|
||||
spacing: 16
|
||||
anchors.fill: parent
|
||||
anchors.margins: 24
|
||||
Icon {
|
||||
source: icon
|
||||
width: 24
|
||||
height: 24
|
||||
color: isChecked ? "#1976D2" : "#666"
|
||||
}
|
||||
Text {
|
||||
text: text
|
||||
font.pointSize: 14
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: isChecked ? "#1976D2" : "#666"
|
||||
}
|
||||
}
|
||||
background: Rectangle {
|
||||
color: isChecked ? "#E3F2FD" : "transparent"
|
||||
radius: 0
|
||||
}
|
||||
}
|
||||
|
||||
component MenuButton: IconButton {
|
||||
iconSource: icon
|
||||
}
|
||||
|
||||
// Placeholder for MailListPage - we'll replace this with a real component later
|
||||
component MailListPage: Item {
|
||||
id: mailListPage
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "#fafafa"
|
||||
Text {
|
||||
text: qsTr("Mail List Placeholder")
|
||||
anchors.centerIn: parent
|
||||
font.pointSize: 16
|
||||
color: "#666"
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-24
@@ -2,28 +2,6 @@ import QtQuick 2.15
|
||||
import QtQuick.Window 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
Window {
|
||||
width: 1024
|
||||
height: 768
|
||||
visible: true
|
||||
title: qsTr("Wino Mail Qt")
|
||||
|
||||
// Use the translator to set the title
|
||||
// Note: we can't directly call translator.tr here because it's a C++ object.
|
||||
// We'll set the title in Component.onCompleted by accessing the context property.
|
||||
Component.onCompleted: {
|
||||
title = translator.tr("appName")
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "#f0f0f0"
|
||||
|
||||
Text {
|
||||
text: qsTr("Welcome to Wino Mail Qt!")
|
||||
anchors.centerIn: parent
|
||||
font.pointSize: 24
|
||||
color: "#333"
|
||||
}
|
||||
}
|
||||
// We'll load the Shell component from Shell.qml
|
||||
Shell {
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import QtQuick 2.15
|
||||
|
||||
ListModel {
|
||||
ListElement {
|
||||
folderName: "Inbox"
|
||||
unreadCount: 5
|
||||
}
|
||||
ListElement {
|
||||
folderName: "Sent"
|
||||
unreadCount: 0
|
||||
}
|
||||
ListElement {
|
||||
folderName: "Drafts"
|
||||
unreadCount: 0
|
||||
}
|
||||
ListElement {
|
||||
folderName: "Trash"
|
||||
unreadCount: 0
|
||||
}
|
||||
ListElement {
|
||||
folderName: "Spam"
|
||||
unreadCount: 0
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -3,9 +3,9 @@
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
#include <QVector>
|
||||
#include "../models/account.h"
|
||||
#include "../models/folder.h"
|
||||
#include "../core/mailitem.h"
|
||||
#include "models/account.h"
|
||||
#include "models/folder.h"
|
||||
#include "mailitem.h"
|
||||
|
||||
namespace WinoMail {
|
||||
namespace Events {
|
||||
@@ -38,7 +38,7 @@ struct FolderAddedEvent : public BaseEvent {
|
||||
};
|
||||
|
||||
struct FolderRemovedEvent : public BaseEvent {
|
||||
String folderId;
|
||||
QString folderId;
|
||||
};
|
||||
|
||||
struct FolderUpdatedEvent : public BaseEvent {
|
||||
@@ -63,12 +63,12 @@ struct AccountUpdatedEvent : public BaseEvent {
|
||||
// Sync events
|
||||
struct SyncStartedEvent : public BaseEvent {
|
||||
int accountId;
|
||||
String folderId; // Optional, empty for full account sync
|
||||
QString folderId; // Optional, empty for full account sync
|
||||
};
|
||||
|
||||
struct SyncFinishedEvent : public BaseEvent {
|
||||
int accountId;
|
||||
String folderId; // Optional, empty for full account sync
|
||||
QString folderId; // Optional, empty for full account sync
|
||||
bool success;
|
||||
QString errorMessage; // If success is false
|
||||
};
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
|
||||
class Translator
|
||||
class Translator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static Translator& instance();
|
||||
~Translator() = default;
|
||||
|
||||
+24
-24
@@ -1,5 +1,4 @@
|
||||
#include "accountdao.h"
|
||||
#include <optional>
|
||||
|
||||
bool AccountDao::insert(const Account& account)
|
||||
{
|
||||
@@ -69,7 +68,7 @@ bool AccountDao::remove(int id)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<Account> AccountDao::findById(int id)
|
||||
Account* AccountDao::findById(int id)
|
||||
{
|
||||
QSqlDatabase& db = DatabaseManager::instance().database();
|
||||
QSqlQuery query(db);
|
||||
@@ -78,21 +77,22 @@ std::optional<Account> AccountDao::findById(int id)
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Failed to find account by id:" << query.lastError().text();
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (query.next()) {
|
||||
Account acc;
|
||||
acc.setId(query.value(0).toInt());
|
||||
acc.setEmail(query.value(1).toString());
|
||||
acc.setDisplayName(query.value(2).toString());
|
||||
acc.setType(static_cast<AccountType>(query.value(3).toInt()));
|
||||
acc.setAccessToken(query.value(4).toString());
|
||||
acc.setRefreshToken(query.value(5).toString());
|
||||
acc.setTokenExpires(query.value(6).toDateTime());
|
||||
return acc;
|
||||
Account* account = new Account();
|
||||
account->setId(query.value("id").toLongLong());
|
||||
account->setEmail(query.value("email").toString());
|
||||
account->setDisplayName(query.value("displayName").toString());
|
||||
account->setType(static_cast<AccountType>(query.value("type").toInt()));
|
||||
account->setAccessToken(query.value("accessToken").toString());
|
||||
account->setRefreshToken(query.value("refreshToken").toString());
|
||||
account->setTokenExpires(query.value("tokenExpires").toDateTime());
|
||||
return account;
|
||||
}
|
||||
return std::nullopt;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QVector<Account> AccountDao::findAll()
|
||||
@@ -119,7 +119,7 @@ QVector<Account> AccountDao::findAll()
|
||||
return accounts;
|
||||
}
|
||||
|
||||
std::optional<Account> AccountDao::findByEmail(const QString& email)
|
||||
Account* AccountDao::findByEmail(const QString& email)
|
||||
{
|
||||
QSqlDatabase& db = DatabaseManager::instance().database();
|
||||
QSqlQuery query(db);
|
||||
@@ -128,19 +128,19 @@ std::optional<Account> AccountDao::findByEmail(const QString& email)
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Failed to find account by email:" << query.lastError().text();
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (query.next()) {
|
||||
Account acc;
|
||||
acc.setId(query.value(0).toInt());
|
||||
acc.setEmail(query.value(1).toString());
|
||||
acc.setDisplayName(query.value(2).toString());
|
||||
acc.setType(static_cast<AccountType>(query.value(3).toInt()));
|
||||
acc.setAccessToken(query.value(4).toString());
|
||||
acc.setRefreshToken(query.value(5).toString());
|
||||
acc.setTokenExpires(query.value(6).toDateTime());
|
||||
Account* acc = new Account();
|
||||
acc->setId(query.value(0).toLongLong());
|
||||
acc->setEmail(query.value(1).toString());
|
||||
acc->setDisplayName(query.value(2).toString());
|
||||
acc->setType(static_cast<AccountType>(query.value(3).toInt()));
|
||||
acc->setAccessToken(query.value(4).toString());
|
||||
acc->setRefreshToken(query.value(5).toString());
|
||||
acc->setTokenExpires(query.value(6).toDateTime());
|
||||
return acc;
|
||||
}
|
||||
return std::nullopt;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
#include <QSqlQuery>
|
||||
#include "folderdao.h"
|
||||
#include <QSqlError>
|
||||
#include <QSqlError>
|
||||
#include <optional>
|
||||
|
||||
bool FolderDao::insert(const Folder& folder)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlError>
|
||||
#include "mailitemdao.h"
|
||||
#include <optional>
|
||||
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
#include "dbchangeprocessor.h"
|
||||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
|
||||
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
|
||||
m_batchTimer->setInterval(5000); // 5 segundos
|
||||
connect(m_batchTimer, &QTimer::timeout, this, &DbChangeProcessor::processBatch);
|
||||
m_batchTimer->start();
|
||||
|
||||
// Suscribirse a todos los eventos relevantes
|
||||
SUBSCRIBE(WinoMail::Events::MailItemAddedEvent,
|
||||
[this](const WinoMail::Events::MailItemAddedEvent& event) {
|
||||
handleMailItemAdded(event);
|
||||
});
|
||||
|
||||
SUBSCRIBE(WinoMail::Events::MailItemRemovedEvent,
|
||||
[this](const WinoMail::Events::MailItemRemovedEvent& event) {
|
||||
handleMailItemRemoved(event);
|
||||
});
|
||||
|
||||
SUBSCRIBE(WinoMail::Events::MailItemUpdatedEvent,
|
||||
[this](const WinoMail::Events::MailItemUpdatedEvent& event) {
|
||||
handleMailItemUpdated(event);
|
||||
});
|
||||
|
||||
SUBSCRIBE(WinoMail::Events::FolderAddedEvent,
|
||||
[this](const WinoMail::Events::FolderAddedEvent& event) {
|
||||
handleFolderAdded(event);
|
||||
});
|
||||
|
||||
SUBSCRIBE(WinoMail::Events::FolderRemovedEvent,
|
||||
[this](const WinoMail::Events::FolderRemovedEvent& event) {
|
||||
handleFolderRemoved(event);
|
||||
});
|
||||
|
||||
SUBSCRIBE(WinoMail::Events::FolderUpdatedEvent,
|
||||
[this](const WinoMail::Events::FolderUpdatedEvent& event) {
|
||||
handleFolderUpdated(event);
|
||||
});
|
||||
|
||||
SUBSCRIBE(WinoMail::Events::AccountAddedEvent,
|
||||
[this](const WinoMail::Events::AccountAddedEvent& event) {
|
||||
handleAccountAdded(event);
|
||||
});
|
||||
|
||||
SUBSCRIBE(WinoMail::Events::AccountRemovedEvent,
|
||||
[this](const WinoMail::Events::AccountRemovedEvent& event) {
|
||||
handleAccountRemoved(event);
|
||||
});
|
||||
|
||||
SUBSCRIBE(WinoMail::Events::AccountUpdatedEvent,
|
||||
[this](const WinoMail::Events::AccountUpdatedEvent& event) {
|
||||
handleAccountUpdated(event);
|
||||
});
|
||||
}
|
||||
|
||||
void DbChangeProcessor::handleMailItemAdded(const WinoMail::Events::MailItemAddedEvent& event)
|
||||
{
|
||||
qDebug() << "DbChangeProcessor: Queuing MailItemAddedEvent for UID:" << event.item.uid;
|
||||
m_mailItemAddedQueue.append(event);
|
||||
}
|
||||
|
||||
void DbChangeProcessor::handleMailItemRemoved(const WinoMail::Events::MailItemRemovedEvent& event)
|
||||
{
|
||||
qDebug() << "DbChangeProcessor: Queuing MailItemRemovedEvent for UID:" << event.itemUid;
|
||||
m_mailItemRemovedQueue.append(event);
|
||||
}
|
||||
|
||||
void DbChangeProcessor::handleMailItemUpdated(const WinoMail::Events::MailItemUpdatedEvent& event)
|
||||
{
|
||||
qDebug() << "DbChangeProcessor: Queuing MailItemUpdatedEvent for UID:" << event.item.uid;
|
||||
m_mailItemUpdatedQueue.append(event);
|
||||
}
|
||||
|
||||
void DbChangeProcessor::handleFolderAdded(const WinoMail::Events::FolderAddedEvent& event)
|
||||
{
|
||||
qDebug() << "DbChangeProcessor: Queuing FolderAddedEvent for folder:" << event.folder.name;
|
||||
m_folderAddedQueue.append(event);
|
||||
}
|
||||
|
||||
void DbChangeProcessor::handleFolderRemoved(const WinoMail::Events::FolderRemovedEvent& event)
|
||||
{
|
||||
qDebug() << "DbChangeProcessor: Queuing FolderRemovedEvent for folder ID:" << event.folderId;
|
||||
m_folderRemovedQueue.append(event);
|
||||
}
|
||||
|
||||
void DbChangeProcessor::handleFolderUpdated(const WinoMail::Events::FolderUpdatedEvent& event)
|
||||
{
|
||||
qDebug() << "DbChangeProcessor: Queuing FolderUpdatedEvent for folder ID:" << event.folder.id();
|
||||
m_folderUpdatedQueue.append(event);
|
||||
}
|
||||
|
||||
void DbChangeProcessor::handleAccountAdded(const WinoMail::Events::AccountAddedEvent& event)
|
||||
{
|
||||
qDebug() << "DbChangeProcessor: Queuing AccountAddedEvent for account:" << event.account.email();
|
||||
m_accountAddedQueue.append(event);
|
||||
}
|
||||
|
||||
void DbChangeProcessor::handleAccountRemoved(const WinoMail::Events::AccountRemovedEvent& event)
|
||||
{
|
||||
qDebug() << "DbChangeProcessor: Queuing AccountRemovedEvent for account ID:" << event.accountId;
|
||||
m_accountRemovedQueue.append(event);
|
||||
}
|
||||
|
||||
void DbChangeProcessor::handleAccountUpdated(const WinoMail::Events::AccountUpdatedEvent& event)
|
||||
{
|
||||
qDebug() << "DbChangeProcessor: Queuing AccountUpdatedEvent for account ID:" << event.account.id();
|
||||
m_accountUpdatedQueue.append(event);
|
||||
}
|
||||
|
||||
void DbChangeProcessor::processBatch()
|
||||
{
|
||||
qDebug() << "DbChangeProcessor: Starting batch processing at" << QDateTime::currentDateTime().toString();
|
||||
|
||||
// Procesar eventos de MailItem añadidos
|
||||
if (!m_mailItemAddedQueue.isEmpty()) {
|
||||
qDebug() << "DbChangeProcessor: Processing" << m_mailItemAddedQueue.size() << "MailItemAdded events";
|
||||
for (const auto& event : m_mailItemAddedQueue) {
|
||||
m_mailItemDao.insert(event.item);
|
||||
}
|
||||
m_mailItemAddedQueue.clear();
|
||||
}
|
||||
|
||||
// Procesar eventos de MailItem eliminados
|
||||
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);
|
||||
}
|
||||
m_mailItemRemovedQueue.clear();
|
||||
}
|
||||
|
||||
// Procesar eventos de MailItem actualizados
|
||||
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);
|
||||
}
|
||||
m_mailItemUpdatedQueue.clear();
|
||||
}
|
||||
|
||||
// Procesar eventos de carpetas añadidas
|
||||
if (!m_folderAddedQueue.isEmpty()) {
|
||||
qDebug() << "DbChangeProcessor: Processing" << m_folderAddedQueue.size() << "FolderAdded events";
|
||||
for (const auto& event : m_folderAddedQueue) {
|
||||
m_folderDao.insert(event.folder);
|
||||
}
|
||||
m_folderAddedQueue.clear();
|
||||
}
|
||||
|
||||
// Procesar eventos de carpetas eliminadas
|
||||
if (!m_folderRemovedQueue.isEmpty()) {
|
||||
qDebug() << "DbChangeProcessor: Processing" << m_folderRemovedQueue.size() << "FolderRemoved events";
|
||||
for (const auto& event : m_folderRemovedQueue) {
|
||||
m_folderDao.remove(event.folderId.toInt());
|
||||
}
|
||||
m_folderRemovedQueue.clear();
|
||||
}
|
||||
|
||||
// Procesar eventos de carpetas actualizadas
|
||||
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);
|
||||
}
|
||||
m_folderUpdatedQueue.clear();
|
||||
}
|
||||
|
||||
// Procesar eventos de cuentas añadidas
|
||||
if (!m_accountAddedQueue.isEmpty()) {
|
||||
qDebug() << "DbChangeProcessor: Processing" << m_accountAddedQueue.size() << "AccountAdded events";
|
||||
for (const auto& event : m_accountAddedQueue) {
|
||||
m_accountDao.insert(event.account);
|
||||
}
|
||||
m_accountAddedQueue.clear();
|
||||
}
|
||||
|
||||
// Procesar eventos de cuentas eliminadas
|
||||
if (!m_accountRemovedQueue.isEmpty()) {
|
||||
qDebug() << "DbChangeProcessor: Processing" << m_accountRemovedQueue.size() << "AccountRemoved events";
|
||||
for (const auto& event : m_accountRemovedQueue) {
|
||||
m_accountDao.remove(event.accountId);
|
||||
}
|
||||
m_accountRemovedQueue.clear();
|
||||
}
|
||||
|
||||
// Procesar eventos de cuentas actualizadas
|
||||
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);
|
||||
}
|
||||
m_accountUpdatedQueue.clear();
|
||||
}
|
||||
|
||||
qDebug() << "DbChangeProcessor: Batch processing completed at" << QDateTime::currentDateTime().toString();
|
||||
}
|
||||
|
||||
DbChangeProcessor::~DbChangeProcessor()
|
||||
{
|
||||
if (m_batchTimer->isActive()) {
|
||||
m_batchTimer->stop();
|
||||
}
|
||||
// Procesar cualquier evento restante antes de destruir
|
||||
processBatch();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef DBCHANGEPROCESSOR_H
|
||||
#define DBCHANGEPROCESSOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QVector>
|
||||
#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;
|
||||
|
||||
private slots:
|
||||
void handleMailItemAdded(const WinoMail::Events::MailItemAddedEvent& event);
|
||||
void handleMailItemRemoved(const WinoMail::Events::MailItemRemovedEvent& event);
|
||||
void handleMailItemUpdated(const WinoMail::Events::MailItemUpdatedEvent& event);
|
||||
void handleFolderAdded(const WinoMail::Events::FolderAddedEvent& event);
|
||||
void handleFolderRemoved(const WinoMail::Events::FolderRemovedEvent& event);
|
||||
void handleFolderUpdated(const WinoMail::Events::FolderUpdatedEvent& event);
|
||||
void handleAccountAdded(const WinoMail::Events::AccountAddedEvent& event);
|
||||
void handleAccountRemoved(const WinoMail::Events::AccountRemovedEvent& event);
|
||||
void handleAccountUpdated(const WinoMail::Events::AccountUpdatedEvent& event);
|
||||
void processBatch();
|
||||
|
||||
private:
|
||||
DatabaseManager& m_db;
|
||||
MailItemDao& m_mailItemDao;
|
||||
FolderDao& m_folderDao;
|
||||
AccountDao& m_accountDao;
|
||||
|
||||
QTimer* m_batchTimer;
|
||||
QVector<WinoMail::Events::MailItemAddedEvent> m_mailItemAddedQueue;
|
||||
QVector<WinoMail::Events::MailItemRemovedEvent> m_mailItemRemovedQueue;
|
||||
QVector<WinoMail::Events::MailItemUpdatedEvent> m_mailItemUpdatedQueue;
|
||||
QVector<WinoMail::Events::FolderAddedEvent> m_folderAddedQueue;
|
||||
QVector<WinoMail::Events::FolderRemovedEvent> m_folderRemovedQueue;
|
||||
QVector<WinoMail::Events::FolderUpdatedEvent> m_folderUpdatedQueue;
|
||||
QVector<WinoMail::Events::AccountAddedEvent> m_accountAddedQueue;
|
||||
QVector<WinoMail::Events::AccountRemovedEvent> m_accountRemovedQueue;
|
||||
QVector<WinoMail::Events::AccountUpdatedEvent> m_accountUpdatedQueue;
|
||||
};
|
||||
|
||||
#endif // DBCHANGEPROCESSOR_H
|
||||
+5
-1
@@ -2,6 +2,7 @@
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include "core/translator.h"
|
||||
#include "db/dbchangeprocessor.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -13,8 +14,11 @@ int main(int argc, char *argv[])
|
||||
qWarning() << "Failed to load translation";
|
||||
}
|
||||
|
||||
// Initialize the DbChangeProcessor to start processing events in batches
|
||||
DbChangeProcessor dbChangeProcessor(&app);
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
engine.rootContext()->setContextProperty("translator", &translator);
|
||||
engine.rootContext()->setContextProperty("translator", static_cast<QObject*>(&translator));
|
||||
|
||||
const QUrl url(QStringLiteral("qrc:/main.qml"));
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QDebug>
|
||||
#include <QUrlQuery>
|
||||
#include <QDateTime>
|
||||
#include <QTimer>
|
||||
|
||||
@@ -25,11 +26,6 @@ GmailSynchronizer::GmailSynchronizer(QObject* parent)
|
||||
m_historyTimer->setInterval(2 * 60 * 1000); // 2 minutos
|
||||
}
|
||||
|
||||
GmailSynchronizer::~GmailSynchronizer()
|
||||
{
|
||||
m_historyTimer->stop();
|
||||
}
|
||||
|
||||
bool GmailSynchronizer::initialize(const Account& account)
|
||||
{
|
||||
// Guardar información de la cuenta
|
||||
@@ -60,10 +56,10 @@ bool GmailSynchronizer::syncFolder(const Folder& folder)
|
||||
}
|
||||
|
||||
qDebug() << "Starting Gmail sync for folder (label):" << folder.name();
|
||||
emit folderSyncStarted(folder.id());
|
||||
emit folderSyncStarted(QString::number(folder.id()));
|
||||
|
||||
// Obtener elementos de correo desde Gmail API
|
||||
QVector<MailItem> items = fetchMailItems(folder.id());
|
||||
QVector<MailItem> items = fetchMailItems(QString::number(folder.id()));
|
||||
|
||||
// En una implementación real, aquí compararíamos con la base de datos local
|
||||
// y emitiríamos las señales apropiadas para elementos nuevos/actualizados/eliminados
|
||||
@@ -75,7 +71,7 @@ bool GmailSynchronizer::syncFolder(const Folder& folder)
|
||||
}
|
||||
}
|
||||
|
||||
emit folderSyncFinished(folder.id(), true);
|
||||
emit folderSyncFinished(QString::number(folder.id()), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -113,7 +109,7 @@ QVector<MailItem> GmailSynchronizer::fetchMailItems(const QString& folderId,
|
||||
|
||||
// Construir la URL para Gmail API
|
||||
// Nota: En Gmail, las carpetas se identifican por su nombre de label (ej: INBOX, DRAFTS, etc.)
|
||||
QString endpoint = String.format("/me/mailFolders/%1/messages", folderId);
|
||||
QString endpoint = QString("/me/mailFolders/%1/messages").arg(folderId);
|
||||
QString url = buildGmailUrl(endpoint);
|
||||
|
||||
// Parámetros de consulta
|
||||
@@ -257,7 +253,7 @@ void GmailSynchronizer::onHistoryTimer()
|
||||
// de todas las etiquetas (esto sería ineficiente en producción)
|
||||
QVector<Folder> folders = getFolders();
|
||||
for (const Folder& folder : folders) {
|
||||
syncFolder(folder.id());
|
||||
syncFolder(Folder(folder.id(), 0, QString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +266,7 @@ QString GmailSynchronizer::buildGmailUrl(const QString& endpoint) const
|
||||
|
||||
QNetworkRequest GmailSynchronizer::createAuthRequest(const QString& url) const
|
||||
{
|
||||
QNetworkRequest request(QUrl(url));
|
||||
QNetworkRequest request{QUrl(url)};
|
||||
request.setRawHeader("Authorization",
|
||||
QString("Bearer %1").arg(m_accessToken).toUtf8());
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "imapsynchronizer.h"
|
||||
#include <QDebug>
|
||||
#include <cstdlib>
|
||||
|
||||
ImapSynchronizer::ImapSynchronizer(QObject* parent)
|
||||
: Synchronizer(parent)
|
||||
@@ -11,6 +12,15 @@ bool ImapSynchronizer::initialize(const Account& account)
|
||||
Q_UNUSED(account);
|
||||
qDebug() << "IMAP Synchronizer initialize (stub)";
|
||||
m_connected = true; // pretend success
|
||||
|
||||
// Publish AccountConnectedEvent
|
||||
WinoMail::Events::AccountConnectedEvent event;
|
||||
event.eventId = generateEventId();
|
||||
event.timestamp = QDateTime::currentDateTimeUtc();
|
||||
event.accountId = account.id();
|
||||
event.provider = "imap";
|
||||
PUBLISH(event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -18,9 +28,36 @@ bool ImapSynchronizer::syncFolder(const Folder& folder)
|
||||
{
|
||||
Q_UNUSED(folder);
|
||||
qDebug() << "IMAP Synchronizer syncFolder (stub)";
|
||||
emit folderSyncStarted(folder.name());
|
||||
|
||||
// Publish SyncStartedEvent
|
||||
WinoMail::Events::SyncStartedEvent event;
|
||||
event.eventId = generateEventId();
|
||||
event.timestamp = QDateTime::currentDateTimeUtc();
|
||||
event.accountId = m_account.id();
|
||||
event.folderId = QString::number(folder.id()); // Assuming folder.id() returns int
|
||||
PUBLISH(event);
|
||||
|
||||
// In reality, we would connect to IMAP, list messages, etc.
|
||||
emit folderSyncFinished(folder.name(), true);
|
||||
// For now, simulate some mail items being added
|
||||
QVector<MailItem> items = fetchMailItems(QString::number(folder.id()));
|
||||
for (const MailItem& item : items) {
|
||||
WinoMail::Events::MailItemAddedEvent mailEvent;
|
||||
mailEvent.eventId = generateEventId();
|
||||
mailEvent.timestamp = QDateTime::currentDateTimeUtc();
|
||||
mailEvent.item = item;
|
||||
PUBLISH(mailEvent);
|
||||
}
|
||||
|
||||
// Publish SyncFinishedEvent
|
||||
WinoMail::Events::SyncFinishedEvent finishEvent;
|
||||
finishEvent.eventId = generateEventId();
|
||||
finishEvent.timestamp = QDateTime::currentDateTimeUtc();
|
||||
finishEvent.accountId = m_account.id();
|
||||
finishEvent.folderId = QString::number(folder.id());
|
||||
finishEvent.success = true;
|
||||
finishEvent.errorMessage = "";
|
||||
PUBLISH(finishEvent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,7 +78,7 @@ QVector<MailItem> ImapSynchronizer::fetchMailItems(const QString& folderId,
|
||||
qDebug() << "IMAP Synchronizer fetchMailItems (stub)";
|
||||
// Return a dummy mail item for testing
|
||||
QVector<MailItem> items;
|
||||
items.append(MailItem(1, "Test Subject", "sender@example.com", "me@example.com",
|
||||
items.append(MailItem(1, 1, "Test Subject", "sender@example.com", "me@example.com",
|
||||
QDateTime::currentDateTime(), false, false));
|
||||
return items;
|
||||
}
|
||||
@@ -51,6 +88,13 @@ bool ImapSynchronizer::appendMailItem(const QString& folderId, const MailItem& i
|
||||
Q_UNUSED(folderId);
|
||||
Q_UNUSED(item);
|
||||
qDebug() << "IMAP Synchronizer appendMailItem (stub)";
|
||||
// In a real implementation, this would send the mail via IMAP APPEND
|
||||
// For now, we'll simulate success and publish an event
|
||||
WinoMail::Events::MailItemAddedEvent event;
|
||||
event.eventId = generateEventId();
|
||||
event.timestamp = QDateTime::currentDateTimeUtc();
|
||||
event.item = item;
|
||||
PUBLISH(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -63,6 +107,18 @@ bool ImapSynchronizer::updateMailItemFlags(const QString& folderId,
|
||||
Q_UNUSED(read);
|
||||
Q_UNUSED(flagged);
|
||||
qDebug() << "IMAP Synchronizer updateMailItemFlags (stub)";
|
||||
// In a real implementation, this would update flags via IMAP STORE
|
||||
// For now, we'll simulate success and publish an update event
|
||||
// We need to fetch the item first to know what changed
|
||||
MailItem item; // This would be fetched from storage
|
||||
item.setId(itemUid.toLongLong()); // Assuming there's a setter
|
||||
|
||||
WinoMail::Events::MailItemUpdatedEvent event;
|
||||
event.eventId = generateEventId();
|
||||
event.timestamp = QDateTime::currentDateTimeUtc();
|
||||
event.item = item;
|
||||
event.changedFields = QStringList() << "read" << "flagged"; // Simplified
|
||||
PUBLISH(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -72,5 +128,21 @@ bool ImapSynchronizer::deleteMailItem(const QString& folderId,
|
||||
Q_UNUSED(folderId);
|
||||
Q_UNUSED(itemUid);
|
||||
qDebug() << "IMAP Synchronizer deleteMailItem (stub)";
|
||||
// In a real implementation, this would delete the mail via IMAP STORE +FLAGS or EXPUNGE
|
||||
// For now, we'll simulate success and publish a removal event
|
||||
WinoMail::Events::MailItemRemovedEvent event;
|
||||
event.eventId = generateEventId();
|
||||
event.timestamp = QDateTime::currentDateTimeUtc();
|
||||
event.itemUid = itemUid;
|
||||
event.folderId = folderId.toInt(); // Assuming folderId is numeric
|
||||
PUBLISH(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper para generar IDs únicos de eventos
|
||||
QString ImapSynchronizer::generateEventId() const
|
||||
{
|
||||
// Simple implementation using timestamp and random component
|
||||
return QString::number(QDateTime::currentMSecsSinceEpoch()) + "_" +
|
||||
QString::number(std::rand());
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
#include "../synchronizer.h"
|
||||
#include <QObject>
|
||||
#include "../../core/eventbus.h"
|
||||
#include "../../core/models/account.h"
|
||||
#include "../../core/models/folder.h"
|
||||
#include "../../core/mailitem.h"
|
||||
|
||||
class ImapSynchronizer : public Synchronizer
|
||||
{
|
||||
@@ -31,4 +35,7 @@ private:
|
||||
QString m_username;
|
||||
QString m_password;
|
||||
bool m_useSsl{true};
|
||||
|
||||
// Helper para generar IDs únicos de eventos
|
||||
QString generateEventId() const;
|
||||
};
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QDebug>
|
||||
#include <QUrlQuery>
|
||||
#include <QDateTime>
|
||||
#include <QTimer>
|
||||
|
||||
@@ -25,11 +26,6 @@ OutlookSynchronizer::OutlookSynchronizer(QObject* parent)
|
||||
m_deltaTimer->setInterval(5 * 60 * 1000); // 5 minutos
|
||||
}
|
||||
|
||||
OutlookSynchronizer::~OutlookSynchronizer()
|
||||
{
|
||||
m_deltaTimer->stop();
|
||||
}
|
||||
|
||||
bool OutlookSynchronizer::initialize(const Account& account)
|
||||
{
|
||||
// Guardar información de la cuenta
|
||||
@@ -60,10 +56,10 @@ bool OutlookSynchronizer::syncFolder(const Folder& folder)
|
||||
}
|
||||
|
||||
qDebug() << "Starting Outlook sync for folder:" << folder.name();
|
||||
emit folderSyncStarted(folder.id());
|
||||
emit folderSyncStarted(QString::number(folder.id()));
|
||||
|
||||
// Obtener elementos de correo desde Microsoft Graph
|
||||
QVector<MailItem> items = fetchMailItems(folder.id());
|
||||
QVector<MailItem> items = fetchMailItems(QString::number(folder.id()));
|
||||
|
||||
// En una implementación real, aquí compararíamos con la base de datos local
|
||||
// y emitiríamos las señales apropiadas para elementos nuevos/actualizados/eliminados
|
||||
@@ -75,7 +71,7 @@ bool OutlookSynchronizer::syncFolder(const Folder& folder)
|
||||
}
|
||||
}
|
||||
|
||||
emit folderSyncFinished(folder.id(), true);
|
||||
emit folderSyncFinished(QString::number(folder.id()), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -264,7 +260,7 @@ QString OutlookSynchronizer::buildGraphUrl(const QString& endpoint) const
|
||||
|
||||
QNetworkRequest OutlookSynchronizer::createAuthRequest(const QString& url) const
|
||||
{
|
||||
QNetworkRequest request(QUrl(url));
|
||||
QNetworkRequest request{QUrl(url)};
|
||||
request.setRawHeader("Authorization",
|
||||
QString("Bearer %1").arg(m_accessToken).toUtf8());
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "FolderListModel.h"
|
||||
#include <QDebug>
|
||||
|
||||
FolderListModel::FolderListModel(QObject *parent)
|
||||
: QAbstractListModel(parent),
|
||||
m_folderDao(FolderDao::instance())
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
int FolderListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
return m_folderNames.size();
|
||||
}
|
||||
|
||||
QVariant FolderListModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() >= m_folderNames.size())
|
||||
return QVariant();
|
||||
|
||||
if (role == FolderNameRole)
|
||||
return m_folderNames.at(index.row());
|
||||
else if (role == UnreadCountRole)
|
||||
return m_unreadCounts.at(index.row());
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> FolderListModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[FolderNameRole] = "folderName";
|
||||
roles[UnreadCountRole] = "unreadCount";
|
||||
return roles;
|
||||
}
|
||||
|
||||
void FolderListModel::refresh()
|
||||
{
|
||||
beginResetModel();
|
||||
// For now, we'll just use hardcoded folders until we implement the DAO properly
|
||||
m_folderNames = {"Inbox", "Sent", "Drafts", "Trash", "Spam"};
|
||||
m_unreadCounts = {5, 0, 0, 0, 0};
|
||||
endResetModel();
|
||||
qDebug() << "FolderListModel refreshed with" << m_folderNames.size() << "folders";
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef FOLDERLISTMODEL_H
|
||||
#define FOLDERLISTMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QHash>
|
||||
#include <QByteArray>
|
||||
#include "../db/dao/folderdao.h"
|
||||
|
||||
class FolderListModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FolderListModel(QObject *parent = nullptr);
|
||||
~FolderListModel() override = default;
|
||||
|
||||
enum FolderRoles {
|
||||
FolderNameRole = Qt::UserRole + 1,
|
||||
UnreadCountRole
|
||||
};
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
// Optional: method to refresh the model from the database
|
||||
void refresh();
|
||||
|
||||
private:
|
||||
QVector<QString> m_folderNames;
|
||||
QVector<int> m_unreadCounts;
|
||||
FolderDao& m_folderDao;
|
||||
};
|
||||
|
||||
#endif // FOLDERLISTMODEL_H
|
||||
Reference in New Issue
Block a user