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:
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,14 @@ Item {
|
|||||||
id: mailListPage
|
id: mailListPage
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
// Models
|
||||||
|
FolderListModel {
|
||||||
|
id: folderModel
|
||||||
|
}
|
||||||
|
EmailListModel {
|
||||||
|
id: emailModel
|
||||||
|
}
|
||||||
|
|
||||||
// Layout: SplitView for resizable panes
|
// Layout: SplitView for resizable panes
|
||||||
SplitView {
|
SplitView {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -18,7 +26,7 @@ Item {
|
|||||||
id: folderListView
|
id: folderListView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
clip: true
|
||||||
model: FolderModel {}
|
model: folderModel
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
height: 40
|
height: 40
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -38,7 +46,18 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
folderListView.currentIndex = index
|
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
|
id: emailListView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
clip: true
|
||||||
model: EmailModel {}
|
model: emailModel
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
height: 60
|
height: 60
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -111,7 +130,11 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
emailListView.currentIndex = index
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -85,34 +85,18 @@ ApplicationWindow {
|
|||||||
StackView {
|
StackView {
|
||||||
id: stackView
|
id: stackView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
initialItem: mailListPage
|
initialItem: MailListPage {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define pages
|
|
||||||
MailListPage {
|
|
||||||
id: mailListPage
|
|
||||||
}
|
|
||||||
// Placeholder for other pages
|
// Placeholder for other pages
|
||||||
Rectangle {
|
CalendarPage {
|
||||||
color: "#f0f0f0"
|
id: calendarPage
|
||||||
Text {
|
|
||||||
text: qsTr("Calendar Page")
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Rectangle {
|
ContactsPage {
|
||||||
color: "#f0f0f0"
|
id: contactsPage
|
||||||
Text {
|
|
||||||
text: qsTr("Contacts Page")
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Rectangle {
|
SettingsPage {
|
||||||
color: "#f0f0f0"
|
id: settingsPage
|
||||||
Text {
|
|
||||||
text: qsTr("Settings Page")
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hamburger button to open drawer
|
// Hamburger button to open drawer
|
||||||
@@ -156,19 +140,3 @@ component NavigationItem: Button {
|
|||||||
component MenuButton: IconButton {
|
component MenuButton: IconButton {
|
||||||
iconSource: icon
|
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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user