Files
wino-mail-dtkqt/src/ui/mainmainwindow.cpp
T

270 lines
9.2 KiB
C++

#include "mainmainwindow.h"
#include "core/models/account.h"
#include "core/mailitem.h"
#include "db/dao/mailitemdao.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFrame>
#include <QDateTime>
#include <QLabel>
MainMainWindow::MainMainWindow(QWidget *parent)
: QMainWindow(parent), m_currentFolderId(-1)
{
setupUI();
connectModels();
setWindowTitle("Wino Mail DTK");
resize(1280, 820);
}
void MainMainWindow::setupUI() {
// === Global stylesheet ===
this->setStyleSheet(
"QMainWindow { background-color: #f5f5f7; }"
"QSplitter::handle { background-color: #d1d1d6; width: 1px; }"
"QTreeView { background-color: #ffffff; border: none; font-family: 'Segoe UI', Helvetica; font-size: 13px; }"
"QToolBar { background-color: #f5f5f7; border-bottom: 1px solid #d1d1d6; spacing: 10px; }"
);
createToolBar();
// === Central widget ===
QWidget *central = new QWidget();
QHBoxLayout *centralLayout = new QHBoxLayout(central);
centralLayout->setContentsMargins(0, 0, 0, 0);
centralLayout->setSpacing(0);
// === Sidebar ===
setupSidebar();
centralLayout->addWidget(m_sidebar);
// === Separator line ===
QFrame *separator = new QFrame();
separator->setFrameShape(QFrame::VLine);
separator->setStyleSheet("color: #d1d1d6;");
centralLayout->addWidget(separator);
// === Stacked pages ===
m_stack = new QStackedWidget();
m_stack->setStyleSheet("background-color: #f5f5f7;");
// Page 0: Mail (folder tree + mail list + reader)
setupMailPage();
m_stack->addWidget(m_mailPage);
// Page 1: Compose
m_composeView = new ComposeView();
connect(m_composeView, &ComposeView::sendRequested, [this](const QString &to, const QString &cc, const QString &bcc, const QString &subject, const QString &body, const QDateTime &scheduleTime) {
QString msg;
if (scheduleTime.isValid()) {
msg = QString("Message scheduled for: %1").arg(scheduleTime.toString("dd/MM/yyyy hh:mm AP"));
} else {
msg = "Message sent (simulated)";
}
if (!cc.isEmpty()) msg += QString(" | Cc: %1").arg(cc);
if (!bcc.isEmpty()) msg += QString(" | Bcc: %1").arg(bcc);
statusBar()->showMessage(msg, 5000);
switchToPage(PageMail);
});
connect(m_composeView, &ComposeView::discardRequested, [this]() {
switchToPage(PageMail);
});
connect(m_composeView, &ComposeView::detachRequested, [this](QWidget *composeView) {
// Detach compose view to a standalone window
QStackedWidget *stack = qobject_cast<QStackedWidget*>(composeView->parentWidget());
if (stack) {
stack->removeWidget(composeView);
}
// Create standalone window
QMainWindow *detachedWin = new QMainWindow();
detachedWin->setWindowTitle("Compose - Wino Mail");
// Assign central widget and ensure it's visible and sized
detachedWin->setCentralWidget(composeView);
composeView->setMinimumSize(800, 600);
composeView->update();
detachedWin->resize(800, 600);
detachedWin->setAttribute(Qt::WA_DeleteOnClose);
detachedWin->show();
statusBar()->showMessage("Compose view detached to separate window", 3000);
});
m_stack->addWidget(m_composeView);
// Page 2: Settings
m_settingsView = new SettingsView();
connect(m_settingsView, &SettingsView::accountAddRequested, [this]() {
statusBar()->showMessage("Account setup dialog would open here", 3000);
});
connect(m_settingsView, &SettingsView::themeChanged, [this](const QString &theme) {
statusBar()->showMessage(QString("Theme changed to: %1 (restart may be required)").arg(theme), 3000);
});
m_stack->addWidget(m_settingsView);
// Page 3: Contacts
m_contactsView = new ContactsView();
m_stack->addWidget(m_contactsView);
// Page 4: Calendar
m_calendarView = new CalendarView();
m_stack->addWidget(m_calendarView);
centralLayout->addWidget(m_stack, 1);
setCentralWidget(central);
// Show mail page by default
switchToPage(PageMail);
}
void MainMainWindow::setupSidebar() {
m_sidebar = new QListWidget();
m_sidebar->setFixedWidth(64);
m_sidebar->setIconSize(QSize(24, 24));
m_sidebar->setSpacing(4);
m_sidebar->setFrameShape(QFrame::NoFrame);
m_sidebar->setStyleSheet(
"QListWidget { background-color: #2c2c2e; border: none; padding: 8px 0; }"
"QListWidget::item { color: #8e8e93; padding: 12px 0; text-align: center; font-size: 10px; border: none; border-radius: 8px; margin: 2px 8px; }"
"QListWidget::item:selected { background-color: #3a3a3c; color: #ffffff; }"
"QListWidget::item:hover { background-color: #3a3a3c; color: #ffffff; }"
);
m_sidebar->addItem("📧\nMail");
m_sidebar->addItem("✏️\nCompose");
m_sidebar->addItem("⚙️\nSettings");
m_sidebar->addItem("👥\nContacts");
m_sidebar->addItem("📅\nCalendar");
m_sidebar->setCurrentRow(0);
connect(m_sidebar, &QListWidget::currentRowChanged, this, &MainMainWindow::onNavChanged);
}
void MainMainWindow::setupMailPage() {
m_mailPage = new QWidget();
QHBoxLayout *mailLayout = new QHBoxLayout(m_mailPage);
mailLayout->setContentsMargins(0, 0, 0, 0);
mailLayout->setSpacing(0);
m_folderSplitter = new QSplitter(Qt::Horizontal);
m_folderSplitter->setHandleWidth(1);
// Folder tree
m_folderTree = new QTreeView();
m_folderTree->setHeaderHidden(true);
m_folderTree->setIndentation(20);
m_folderTree->setMinimumWidth(220);
m_folderTree->setMaximumWidth(350);
m_folderTree->setFrameShape(QFrame::NoFrame);
m_folderTree->setExpandsOnDoubleClick(true);
m_folderSplitter->addWidget(m_folderTree);
// Mail list (QTableView with sorting)
m_mailListView = new MailListView();
connect(m_mailListView, &MailListView::emailSelected, this, &MainMainWindow::onEmailSelected);
connect(m_mailListView, &MailListView::composeRequested, this, &MainMainWindow::onComposeRequested);
m_folderSplitter->addWidget(m_mailListView);
// Reader
m_emailViewer = new ReaderView();
m_emailViewer->setMinimumWidth(350);
connect(m_emailViewer, &ReaderView::replyRequested, this, &MainMainWindow::onReaderReplyRequested);
m_folderSplitter->addWidget(m_emailViewer);
// Default sizes: folder 240, list 380, reader flex
m_folderSplitter->setSizes({240, 380, 600});
mailLayout->addWidget(m_folderSplitter);
}
void MainMainWindow::connectModels() {
m_accountService = new AccountService(this);
m_mailService = new MailService(this);
m_folderModel = new FolderListModel(m_accountService, this);
m_emailModel = new EmailListModel(this);
m_folderTree->setModel(m_folderModel);
m_mailListView->setModel(m_emailModel);
m_folderTree->expandAll();
connect(m_folderTree, &QTreeView::clicked, this, &MainMainWindow::onFolderSelected);
}
void MainMainWindow::onNavChanged(int index) {
switchToPage(static_cast<Page>(index));
}
void MainMainWindow::switchToPage(int pageIndex) {
m_stack->setCurrentIndex(pageIndex);
m_sidebar->blockSignals(true);
m_sidebar->setCurrentRow(pageIndex);
m_sidebar->blockSignals(false);
// Show/hide toolbar actions per page
}
void MainMainWindow::onFolderSelected(const QModelIndex &index) {
if (!index.isValid()) return;
int itemType = index.data(FolderListModel::ItemTypeRole).toInt();
if (itemType == FolderTreeItem::FolderNode) {
m_currentFolderId = index.data(FolderListModel::FolderIdRole).toInt();
m_emailModel->setFolderId(m_currentFolderId);
m_emailModel->refresh();
}
}
void MainMainWindow::onEmailSelected(int mailId) {
std::optional<MailItem> item = MailItemDao::findById(mailId);
if (!item.has_value()) {
m_emailViewer->setMailItem(nullptr);
return;
}
MailItem &mail = item.value();
if (!mail.isRead()) {
mail.setRead(true);
MailItemDao::update(mail);
}
m_emailViewer->setMailItem(&mail);
}
void MainMainWindow::onComposeRequested() {
switchToPage(PageCompose);
}
void MainMainWindow::onReaderReplyRequested(const MailItem *item) {
if (item) {
m_composeView->setTo(item->sender());
m_composeView->setSubject("Re: " + item->subject());
}
switchToPage(PageCompose);
}
void MainMainWindow::onNewMessage() {
switchToPage(PageCompose);
}
void MainMainWindow::createToolBar() {
m_toolBar = addToolBar("Main Toolbar");
m_toolBar->setMovable(false);
QAction *newMsgAction = m_toolBar->addAction("✉ New Message");
m_toolBar->addSeparator();
QAction *syncAction = m_toolBar->addAction("⟳ Sync/Refresh");
QAction *deleteAction = m_toolBar->addAction("🗑 Delete");
connect(newMsgAction, &QAction::triggered, this, &MainMainWindow::onNewMessage);
connect(syncAction, &QAction::triggered, [this]() {
if (m_currentFolderId >= 0) {
m_emailModel->refresh();
statusBar()->showMessage("Refreshed", 2000);
}
});
connect(deleteAction, &QAction::triggered, [this]() {
statusBar()->showMessage("Delete would be implemented here", 3000);
});
}