Complete Phase 4: Basic UI with QML - MailListPage with folder/email navigation, models connected to DAOs, placeholder pages for Calendar/Contacts/Settings

This commit is contained in:
Padrino
2026-05-17 01:52:34 +02:00
parent acec320222
commit 822ed5db47
7 changed files with 235 additions and 43 deletions
+19
View File
@@ -0,0 +1,19 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Item {
id: calendarPage
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "#fafafa"
Text {
text: qsTr("Calendar Page - Placeholder")
anchors.centerIn: parent
font.pointSize: 16
color: "#666"
}
}
}
+19
View File
@@ -0,0 +1,19 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Item {
id: contactsPage
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "#fafafa"
Text {
text: qsTr("Contacts Page - Placeholder")
anchors.centerIn: parent
font.pointSize: 16
color: "#666"
}
}
}
+27 -4
View File
@@ -6,6 +6,14 @@ Item {
id: mailListPage
anchors.fill: parent
// Models
FolderListModel {
id: folderModel
}
EmailListModel {
id: emailModel
}
// Layout: SplitView for resizable panes
SplitView {
anchors.fill: parent
@@ -18,7 +26,7 @@ Item {
id: folderListView
anchors.fill: parent
clip: true
model: FolderModel {}
model: folderModel
delegate: Item {
height: 40
Layout.fillWidth: true
@@ -38,7 +46,18 @@ Item {
anchors.fill: parent
onClicked: {
folderListView.currentIndex = index
// TODO: Load emails for selected folder
// Load emails for selected folder
// For now, we'll map folder names to IDs (hardcoded for demo)
var folderId = 0; // Inbox
switch (folderName) {
case "Inbox": folderId = 0; break;
case "Sent": folderId = 1; break;
case "Drafts": folderId = 2; break;
case "Trash": folderId = 3; break;
case "Spam": folderId = 4; break;
default: folderId = 0;
}
emailModel.setFolderId(folderId);
}
}
}
@@ -60,7 +79,7 @@ Item {
id: emailListView
anchors.fill: parent
clip: true
model: EmailModel {}
model: emailModel
delegate: Item {
height: 60
Layout.fillWidth: true
@@ -111,7 +130,11 @@ Item {
anchors.fill: parent
onClicked: {
emailListView.currentIndex = index
// TODO: Show email preview in the bottom pane
// Show email preview in the bottom pane
// For demo, we'll show some basic info
emailPreview.text = "From: " + senderName + "\n" +
"Subject: " + subject + "\n" +
"Date: " + time.toString()
}
}
}
+19
View File
@@ -0,0 +1,19 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Item {
id: settingsPage
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "#fafafa"
Text {
text: qsTr("Settings Page - Placeholder")
anchors.centerIn: parent
font.pointSize: 16
color: "#666"
}
}
}
+7 -39
View File
@@ -85,34 +85,18 @@ ApplicationWindow {
StackView {
id: stackView
anchors.fill: parent
initialItem: mailListPage
initialItem: MailListPage {}
}
// Define pages
MailListPage {
id: mailListPage
}
// Placeholder for other pages
Rectangle {
color: "#f0f0f0"
Text {
text: qsTr("Calendar Page")
anchors.centerIn: parent
}
CalendarPage {
id: calendarPage
}
Rectangle {
color: "#f0f0f0"
Text {
text: qsTr("Contacts Page")
anchors.centerIn: parent
}
ContactsPage {
id: contactsPage
}
Rectangle {
color: "#f0f0f0"
Text {
text: qsTr("Settings Page")
anchors.centerIn: parent
}
SettingsPage {
id: settingsPage
}
// Hamburger button to open drawer
@@ -155,20 +139,4 @@ component NavigationItem: Button {
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"
}
}
}
+98
View File
@@ -0,0 +1,98 @@
#include "EmailListModel.h"
#include <QDebug>
#include <QDateTime>
EmailListModel::EmailListModel(QObject *parent)
: QAbstractListModel(parent),
m_mailItemDao(MailItemDao::instance())
{
refresh();
}
int EmailListModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return m_emails.size();
}
QVariant EmailListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= m_emails.size())
return QVariant();
const MailItem& item = m_emails.at(index.row());
switch (role) {
case IdRole:
return item.id();
case SubjectRole:
return item.subject();
case SenderRole:
return item.sender();
case RecipientRole:
return item.recipient();
case DateRole:
return item.date();
case ReadRole:
return item.isRead();
case FlaggedRole:
return item.isFlagged();
case AttachmentsRole:
return QVariant::fromValue(item.attachments());
case FileIdRole:
return item.fileId();
case SizeRole:
return item.size();
case MessageIdRole:
return item.messageId();
case SenderInitialRole: {
QString sender = item.sender();
if (sender.isEmpty())
return QString();
// Get first character, or first non-space character?
// Simple: first character of the sender string
return QString(sender.at(0)).toUpper();
}
default:
return QVariant();
}
}
QHash<int, QByteArray> EmailListModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[IdRole] = "id";
roles[SubjectRole] = "subject";
roles[SenderRole] = "sender";
roles[RecipientRole] = "recipient";
roles[DateRole] = "date";
roles[ReadRole] = "read";
roles[FlaggedRole] = "flagged";
roles[AttachmentsRole] = "attachments";
roles[FileIdRole] = "fileId";
roles[SizeRole] = "size";
roles[MessageIdRole] = "messageId";
roles[SenderInitialRole] = "senderInitial";
return roles;
}
void EmailListModel::setFolderId(int folderId)
{
if (m_folderId == folderId)
return;
m_folderId = folderId;
refresh();
}
void EmailListModel::refresh()
{
beginResetModel();
if (m_folderId == -1) {
m_emails = m_mailItemDao.findAll();
} else {
m_emails = m_mailItemDao.findByFolderId(m_folderId);
}
endResetModel();
qDebug() << "EmailListModel refreshed with" << m_emails.size() << "emails for folderId" << m_folderId;
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef EMAILLISTMODEL_H
#define EMAILLISTMODEL_H
#include <QAbstractListModel>
#include <QHash>
#include <QByteArray>
#include "../db/dao/mailitemdao.h"
class EmailListModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit EmailListModel(QObject *parent = nullptr);
~EmailListModel() override = default;
enum EmailRoles {
IdRole = Qt::UserRole + 1,
SubjectRole,
SenderRole,
RecipientRole,
DateRole,
ReadRole,
FlaggedRole,
AttachmentsRole,
FileIdRole,
SizeRole,
MessageIdRole,
SenderInitialRole // computed from sender
};
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;
// Set the folderId to filter emails; -1 means all folders
void setFolderId(int folderId);
// Refresh the model from the database based on current folderId
void refresh();
private:
QVector<MailItem> m_emails;
int m_folderId{-1}; // -1 means all folders
MailItemDao& m_mailItemDao;
};
#endif // EMAILLISTMODEL_H