feat: comprehensive Wino Mail updates

- ReaderView: complete rewrite with CSS styling, headers, attachments, zoom, find, dark mode, image blocking
- Categories: DAO + UI tree widget with colors, nested categories, assignment
- Rules engine: DAO + evaluation + actions (move, mark read, flag, delete, category, forward)
- Templates: DAO + editor + manager with variables support
- Signatures: DAO + manager + auto-per-account + manual selector in compose
- ComposeView: signature combo, template selector, auto-signature on new email
- MainWindow: frameless with rounded corners, 1px border, resize from edges, no status bar
- Database: new tables (Category, MailCategory, Rule, Template, Signature) with indexes
This commit is contained in:
2026-08-23 14:49:58 +02:00
parent 5fcedfa129
commit 0bb8738607
7399 changed files with 44711 additions and 209 deletions
+65
View File
@@ -33,6 +33,55 @@ void MailListView::setupUI() {
layout->addWidget(headerBar);
// Search bar
QWidget *searchBar = new QWidget();
searchBar->setFixedHeight(44);
searchBar->setStyleSheet("background-color: #f5f5f7; border-bottom: 1px solid #d1d1d6;");
QHBoxLayout *searchLayout = new QHBoxLayout(searchBar);
searchLayout->setContentsMargins(12, 4, 12, 4);
searchLayout->setSpacing(8);
m_searchEdit = new QLineEdit();
m_searchEdit->setPlaceholderText("Buscar correos…");
m_searchEdit->setClearButtonEnabled(true);
m_searchEdit->setStyleSheet(
"QLineEdit { background: white; border: 1px solid #d1d1d6; border-radius: 6px; "
"padding: 6px 12px; font-size: 13px; color: #1d1d1f; }"
"QLineEdit:focus { border: 2px solid #0071e3; }"
);
searchLayout->addWidget(m_searchEdit);
connect(m_searchEdit, &QLineEdit::textChanged, this, &MailListView::onSearchTextChanged);
layout->addWidget(searchBar);
// Filter bar
QWidget *filterBar = new QWidget();
filterBar->setFixedHeight(36);
filterBar->setStyleSheet("background-color: #f5f5f7; border-bottom: 1px solid #d1d1d6;");
QHBoxLayout *filterLayout = new QHBoxLayout(filterBar);
filterLayout->setContentsMargins(12, 2, 12, 2);
filterLayout->setSpacing(12);
m_unreadOnlyCheck = new QCheckBox("No leídos");
m_unreadOnlyCheck->setStyleSheet("QCheckBox { font-size: 12px; color: #333; }");
filterLayout->addWidget(m_unreadOnlyCheck);
m_flaggedOnlyCheck = new QCheckBox("Marcados");
m_flaggedOnlyCheck->setStyleSheet("QCheckBox { font-size: 12px; color: #333; }");
filterLayout->addWidget(m_flaggedOnlyCheck);
m_hasAttachmentsCheck = new QCheckBox("Con adjuntos");
m_hasAttachmentsCheck->setStyleSheet("QCheckBox { font-size: 12px; color: #333; }");
filterLayout->addWidget(m_hasAttachmentsCheck);
filterLayout->addStretch();
connect(m_unreadOnlyCheck, &QCheckBox::toggled, this, &MailListView::onFilterChanged);
connect(m_flaggedOnlyCheck, &QCheckBox::toggled, this, &MailListView::onFilterChanged);
connect(m_hasAttachmentsCheck, &QCheckBox::toggled, this, &MailListView::onFilterChanged);
layout->addWidget(filterBar);
// Table
m_tableView = new QTableView();
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
@@ -55,6 +104,8 @@ void MailListView::setupUI() {
m_proxyModel->setSortRole(EmailListModel::DateRole);
m_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
m_proxyModel->setDynamicSortFilter(true);
m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
m_proxyModel->setFilterKeyColumn(-1); // Search all columns
m_tableView->setModel(m_proxyModel);
@@ -90,4 +141,18 @@ void MailListView::onRowSelected(const QModelIndex &index) {
QModelIndex sourceIndex = m_proxyModel->mapToSource(index);
int mailId = sourceIndex.data(EmailListModel::IdRole).toInt();
emit emailSelected(mailId);
}
void MailListView::onSearchTextChanged(const QString &text) {
if (auto *model = qobject_cast<EmailListModel*>(m_proxyModel->sourceModel())) {
model->setSearchFilter(text);
}
}
void MailListView::onFilterChanged() {
if (auto *model = qobject_cast<EmailListModel*>(m_proxyModel->sourceModel())) {
model->setShowUnreadOnly(m_unreadOnlyCheck->isChecked());
model->setShowFlaggedOnly(m_flaggedOnlyCheck->isChecked());
model->setShowHasAttachments(m_hasAttachmentsCheck->isChecked());
}
}