Base: fix compile errors in wino-mail-dtkqt (composeview UI, initializeComposition, startNewEmail, authenticator includes)

This commit is contained in:
2026-06-23 01:34:13 +02:00
parent 2a3a1a0470
commit 967231db3b
91 changed files with 43095 additions and 13646 deletions
+554
View File
@@ -0,0 +1,554 @@
#include "ui/accountsetupdialog.h"
#include <QMessageBox>
#include <QScrollArea>
#include <QFrame>
#include <QDebug>
#include <QRegularExpression>
#include <QRegularExpressionValidator>
// ─────────────────────── Constructor ───────────────────────
AccountSetupDialog::AccountSetupDialog(AccountService *accountService, QWidget *parent)
: QDialog(parent)
, m_accountService(accountService)
, m_selectedProvider(0)
, m_accountCreatedOk(false)
{
m_authTimeoutTimer = new QTimer(this);
m_authTimeoutTimer->setSingleShot(true);
connect(m_authTimeoutTimer, &QTimer::timeout, this, &AccountSetupDialog::onAuthTimeout);
if (m_accountService) {
connect(m_accountService, &AccountService::accountAdded,
this, &AccountSetupDialog::onAccountAdded);
}
setupUI();
}
// ─────────────────────── UI Setup ───────────────────────
void AccountSetupDialog::setupUI()
{
setWindowTitle("Añadir Cuenta de Correo — Wino Mail");
setMinimumSize(600, 500);
resize(660, 520);
// ── Global stylesheet ──
setStyleSheet(
"AccountSetupDialog { background: #f5f5f7; }"
"QLabel { color: #1d1d1f; }"
"QLineEdit {"
" background: #fff; border: 1px solid #d1d1d6; border-radius: 6px;"
" padding: 8px 12px; font-size: 13px; color: #1d1d1f;"
"}"
"QLineEdit:focus { border: 2px solid #0071e3; }"
"QRadioButton { font-size: 14px; padding: 6px 0; }"
"QCheckBox { font-size: 13px; }"
"QPushButton {"
" font-weight: 600; font-size: 13px; padding: 8px 20px; border-radius: 6px;"
"}"
);
QVBoxLayout *root = new QVBoxLayout(this);
root->setContentsMargins(24, 24, 24, 18);
root->setSpacing(16);
// ── Stacked pages ──
m_stack = new QStackedWidget(this);
m_stack->addWidget(createProviderPage()); // 0
m_stack->addWidget(createOAuthPage()); // 1
m_stack->addWidget(createImapPage()); // 2
m_stack->addWidget(createProgressPage()); // 3
root->addWidget(m_stack, 1);
// ── Separator ──
QFrame *sep = new QFrame();
sep->setFrameShape(QFrame::HLine);
sep->setStyleSheet("color: #d1d1d6;");
root->addWidget(sep);
// ── Navigation buttons ──
QHBoxLayout *nav = new QHBoxLayout();
m_btnBack = new QPushButton("← Atrás");
m_btnBack->setStyleSheet(
"QPushButton { background: #fff; color: #0071e3; border: 1px solid #0071e3; }"
"QPushButton:hover { background: #e8f0fe; }"
);
m_btnCancel = new QPushButton("Cancelar");
m_btnCancel->setStyleSheet(
"QPushButton { background: #e5e5ea; color: #1d1d1f; border: none; }"
"QPushButton:hover { background: #d1d1d6; }"
);
m_btnNext = new QPushButton("Siguiente →");
m_btnNext->setStyleSheet(
"QPushButton { background: #0071e3; color: white; border: none; }"
"QPushButton:hover { background: #005bb5; }"
"QPushButton:disabled { background: #a0c4ff; color: #e0e0e0; }"
);
nav->addWidget(m_btnBack);
nav->addStretch();
nav->addWidget(m_btnCancel);
nav->addSpacing(8);
nav->addWidget(m_btnNext);
root->addLayout(nav);
connect(m_btnBack, &QPushButton::clicked, this, &AccountSetupDialog::onBackClicked);
connect(m_btnNext, &QPushButton::clicked, this, &AccountSetupDialog::onNextClicked);
connect(m_btnCancel, &QPushButton::clicked, this, &AccountSetupDialog::onCancelClicked);
goToPage(PageProvider);
}
// ─────────────────── Page 0: Provider ───────────────────
QWidget* AccountSetupDialog::createProviderPage()
{
QWidget *page = new QWidget();
QVBoxLayout *lay = new QVBoxLayout(page);
lay->setContentsMargins(10, 10, 10, 10);
lay->setSpacing(20);
// Title
QLabel *title = new QLabel("Añadir nueva cuenta");
title->setStyleSheet("font-size: 22px; font-weight: 700; color: #1d1d1f;");
title->setAlignment(Qt::AlignCenter);
QLabel *subtitle = new QLabel("Selecciona el tipo de cuenta que deseas configurar:");
subtitle->setStyleSheet("font-size: 14px; color: #8e8e93;");
subtitle->setWordWrap(true);
subtitle->setAlignment(Qt::AlignCenter);
lay->addWidget(title);
lay->addWidget(subtitle);
lay->addSpacing(10);
// Provider cards
m_providerGroup = new QButtonGroup(this);
auto makeRadio = [&](const QString &text, const QString &desc, int id) -> QWidget* {
QWidget *card = new QWidget();
card->setStyleSheet(
"QWidget { background: #fff; border: 1px solid #e0e0e5; border-radius: 10px; }"
"QWidget:hover { border-color: #0071e3; }"
);
QHBoxLayout *h = new QHBoxLayout(card);
h->setContentsMargins(16, 12, 16, 12);
QRadioButton *radio = new QRadioButton(text);
radio->setStyleSheet("font-size: 15px; font-weight: 600;");
m_providerGroup->addButton(radio, id);
QLabel *descLabel = new QLabel(desc);
descLabel->setStyleSheet("font-size: 12px; color: #8e8e93;");
descLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
h->addWidget(radio, 1);
h->addWidget(descLabel);
return card;
};
lay->addWidget(makeRadio("🔴 Google / Gmail", "OAuth2 seguro", 0));
lay->addWidget(makeRadio("🔵 Microsoft / Outlook", "OAuth2 seguro", 1));
lay->addWidget(makeRadio("⚙️ IMAP / SMTP", "Servidor personalizado", 2));
m_providerGroup->button(0)->setChecked(true);
connect(m_providerGroup, QOverload<int>::of(&QButtonGroup::idClicked),
this, &AccountSetupDialog::onProviderSelected);
lay->addStretch();
return page;
}
// ─────────────────── Page 1: OAuth ───────────────────
QWidget* AccountSetupDialog::createOAuthPage()
{
QWidget *page = new QWidget();
QVBoxLayout *lay = new QVBoxLayout(page);
lay->setContentsMargins(10, 10, 10, 10);
lay->setSpacing(14);
QLabel *title = new QLabel("Autenticación OAuth2");
title->setStyleSheet("font-size: 18px; font-weight: 700;");
lay->addWidget(title);
QLabel *info = new QLabel(
"Se abrirá tu navegador web para que inicies sesión de forma segura.\n"
"Wino Mail no almacena tu contraseña, solo el token de acceso autorizado.\n\n"
"Pasos:\n"
" 1. Introduce tu dirección de correo.\n"
" 2. Pulsa «Autenticar en Navegador».\n"
" 3. Completa el inicio de sesión en la ventana del navegador.\n"
" 4. Al terminar, esta ventana se actualizará automáticamente."
);
info->setWordWrap(true);
info->setStyleSheet("font-size: 13px; color: #555; line-height: 1.5;");
lay->addWidget(info);
lay->addSpacing(6);
QLabel *emailLabel = new QLabel("Correo electrónico:");
emailLabel->setStyleSheet("font-weight: 600; font-size: 13px;");
lay->addWidget(emailLabel);
m_oauthEmailEdit = new QLineEdit();
m_oauthEmailEdit->setPlaceholderText("tu-correo@gmail.com");
QRegularExpression rx(R"([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})");
m_oauthEmailEdit->setValidator(new QRegularExpressionValidator(rx, this));
lay->addWidget(m_oauthEmailEdit);
lay->addSpacing(8);
m_btnOAuthStart = new QPushButton("🔑 Autenticar en Navegador");
m_btnOAuthStart->setMinimumHeight(40);
m_btnOAuthStart->setStyleSheet(
"QPushButton { background: #34a853; color: white; border: none; font-size: 14px; font-weight: 700; border-radius: 8px; }"
"QPushButton:hover { background: #2d9249; }"
"QPushButton:disabled { background: #a8d5b8; color: #e0e0e0; }"
);
connect(m_btnOAuthStart, &QPushButton::clicked, this, &AccountSetupDialog::startOAuthAuthentication);
lay->addWidget(m_btnOAuthStart);
m_oauthStatusLabel = new QLabel("Esperando…");
m_oauthStatusLabel->setStyleSheet("font-size: 12px; color: #8e8e93; font-style: italic;");
m_oauthStatusLabel->setAlignment(Qt::AlignCenter);
lay->addWidget(m_oauthStatusLabel);
lay->addStretch();
return page;
}
// ─────────────────── Page 2: IMAP ───────────────────
QWidget* AccountSetupDialog::createImapPage()
{
QWidget *page = new QWidget();
QVBoxLayout *outerLay = new QVBoxLayout(page);
outerLay->setContentsMargins(10, 10, 10, 10);
QLabel *title = new QLabel("Configuración IMAP / SMTP");
title->setStyleSheet("font-size: 18px; font-weight: 700;");
outerLay->addWidget(title);
QLabel *info = new QLabel("Introduce los datos de tu servidor de correo. "
"Consulta a tu proveedor si no conoces los datos del servidor.");
info->setWordWrap(true);
info->setStyleSheet("font-size: 12px; color: #8e8e93; margin-bottom: 8px;");
outerLay->addWidget(info);
// Scrollable form
QScrollArea *scroll = new QScrollArea();
scroll->setWidgetResizable(true);
scroll->setFrameShape(QFrame::NoFrame);
QWidget *formWidget = new QWidget();
QFormLayout *form = new QFormLayout(formWidget);
form->setSpacing(10);
form->setContentsMargins(0, 8, 12, 8);
form->setLabelAlignment(Qt::AlignRight);
m_imapEmailEdit = new QLineEdit();
m_imapEmailEdit->setPlaceholderText("usuario@empresa.com");
m_imapNameEdit = new QLineEdit();
m_imapNameEdit->setPlaceholderText("Nombre a mostrar (ej. Javier)");
m_imapPasswordEdit = new QLineEdit();
m_imapPasswordEdit->setEchoMode(QLineEdit::Password);
m_imapPasswordEdit->setPlaceholderText("Contraseña");
m_imapHostEdit = new QLineEdit();
m_imapHostEdit->setPlaceholderText("imap.empresa.com");
m_imapPortEdit = new QLineEdit();
m_imapPortEdit->setPlaceholderText("993");
m_imapPortEdit->setValidator(new QIntValidator(1, 65535, this));
m_imapPortEdit->setMaximumWidth(100);
m_smtpHostEdit = new QLineEdit();
m_smtpHostEdit->setPlaceholderText("smtp.empresa.com");
m_smtpPortEdit = new QLineEdit();
m_smtpPortEdit->setPlaceholderText("587");
m_smtpPortEdit->setValidator(new QIntValidator(1, 65535, this));
m_smtpPortEdit->setMaximumWidth(100);
m_sslCheckbox = new QCheckBox("Usar conexión segura (SSL/TLS)");
m_sslCheckbox->setChecked(true);
form->addRow("Correo:", m_imapEmailEdit);
form->addRow("Nombre:", m_imapNameEdit);
form->addRow("Contraseña:", m_imapPasswordEdit);
// Visual separator
QFrame *line = new QFrame();
line->setFrameShape(QFrame::HLine);
line->setStyleSheet("color: #e0e0e5;");
form->addRow(line);
QLabel *serverHeader = new QLabel("Servidores");
serverHeader->setStyleSheet("font-weight: 700; font-size: 13px; color: #0071e3;");
form->addRow(serverHeader);
form->addRow("Servidor IMAP:", m_imapHostEdit);
form->addRow("Puerto IMAP:", m_imapPortEdit);
form->addRow("Servidor SMTP:", m_smtpHostEdit);
form->addRow("Puerto SMTP:", m_smtpPortEdit);
form->addRow("", m_sslCheckbox);
scroll->setWidget(formWidget);
outerLay->addWidget(scroll, 1);
return page;
}
// ─────────────────── Page 3: Progress ───────────────────
QWidget* AccountSetupDialog::createProgressPage()
{
QWidget *page = new QWidget();
QVBoxLayout *lay = new QVBoxLayout(page);
lay->setContentsMargins(20, 40, 20, 20);
lay->setAlignment(Qt::AlignCenter);
m_progressIcon = new QLabel("");
m_progressIcon->setStyleSheet("font-size: 56px;");
m_progressIcon->setAlignment(Qt::AlignCenter);
m_progressText = new QLabel("Conectando al servidor…");
m_progressText->setStyleSheet("font-size: 16px; font-weight: 600; color: #1d1d1f;");
m_progressText->setAlignment(Qt::AlignCenter);
m_progressDetail = new QLabel("Validando credenciales y configuración del servidor de correo.");
m_progressDetail->setWordWrap(true);
m_progressDetail->setStyleSheet("font-size: 13px; color: #8e8e93;");
m_progressDetail->setAlignment(Qt::AlignCenter);
lay->addWidget(m_progressIcon);
lay->addSpacing(16);
lay->addWidget(m_progressText);
lay->addSpacing(8);
lay->addWidget(m_progressDetail);
lay->addStretch();
return page;
}
// ─────────────────── Navigation ───────────────────
void AccountSetupDialog::goToPage(int page)
{
m_stack->setCurrentIndex(page);
updateNavButtons();
}
void AccountSetupDialog::updateNavButtons()
{
int page = m_stack->currentIndex();
m_btnBack->setVisible(page > 0 && page != PageProgress);
m_btnCancel->setVisible(page != PageProgress || !m_accountCreatedOk);
switch (page) {
case PageProvider:
m_btnNext->setText("Siguiente →");
m_btnNext->setEnabled(true);
m_btnNext->setVisible(true);
break;
case PageOAuth:
m_btnNext->setVisible(false); // OAuth flow is driven by the authenticate button
break;
case PageImap:
m_btnNext->setText("Conectar");
m_btnNext->setEnabled(true);
m_btnNext->setVisible(true);
break;
case PageProgress:
if (m_accountCreatedOk) {
m_btnNext->setText("Finalizar ✓");
m_btnNext->setEnabled(true);
m_btnNext->setVisible(true);
m_btnBack->setVisible(false);
m_btnCancel->setVisible(false);
} else {
m_btnNext->setVisible(false);
}
break;
}
}
void AccountSetupDialog::onProviderSelected(int id)
{
m_selectedProvider = id;
}
void AccountSetupDialog::onNextClicked()
{
int page = m_stack->currentIndex();
if (page == PageProvider) {
if (m_selectedProvider == 2) {
goToPage(PageImap);
} else {
// Update OAuth page subtitle based on provider
goToPage(PageOAuth);
}
}
else if (page == PageImap) {
submitImapAccount();
}
else if (page == PageProgress) {
accept(); // Finalizar
}
}
void AccountSetupDialog::onBackClicked()
{
int page = m_stack->currentIndex();
if (page == PageOAuth || page == PageImap) {
m_authTimeoutTimer->stop();
goToPage(PageProvider);
}
}
void AccountSetupDialog::onCancelClicked()
{
m_authTimeoutTimer->stop();
reject();
}
// ─────────────────── OAuth Flow ───────────────────
void AccountSetupDialog::startOAuthAuthentication()
{
QString email = m_oauthEmailEdit->text().trimmed();
if (email.isEmpty()) {
QMessageBox::warning(this, "Validación",
"Introduce tu dirección de correo electrónico.");
return;
}
m_btnOAuthStart->setEnabled(false);
m_oauthStatusLabel->setText("Abriendo navegador… Completa el inicio de sesión allí.");
m_oauthStatusLabel->setStyleSheet("font-size: 12px; color: #0071e3; font-weight: 600;");
QString provider = (m_selectedProvider == 0) ? "gmail" : "outlook";
// Start authentication via AccountService (opens browser)
m_accountService->startAuthentication(email, provider);
// Start timeout timer (120 seconds to complete OAuth)
m_authTimeoutTimer->start(120000);
qDebug() << "[AccountSetupDialog] OAuth started for" << email << "provider:" << provider;
}
void AccountSetupDialog::onAuthTimeout()
{
if (m_stack->currentIndex() == PageOAuth) {
m_btnOAuthStart->setEnabled(true);
m_oauthStatusLabel->setText("⚠️ Tiempo de espera agotado. Inténtalo de nuevo.");
m_oauthStatusLabel->setStyleSheet("font-size: 12px; color: #ff3b30; font-weight: 600;");
}
}
// ─────────────────── IMAP Flow ───────────────────
void AccountSetupDialog::submitImapAccount()
{
QString email = m_imapEmailEdit->text().trimmed();
QString name = m_imapNameEdit->text().trimmed();
QString password = m_imapPasswordEdit->text().trimmed();
QString imapHost = m_imapHostEdit->text().trimmed();
QString imapPort = m_imapPortEdit->text().trimmed();
QString smtpHost = m_smtpHostEdit->text().trimmed();
QString smtpPort = m_smtpPortEdit->text().trimmed();
// Validation
if (email.isEmpty()) {
QMessageBox::warning(this, "Campo requerido", "Introduce tu dirección de correo.");
return;
}
if (password.isEmpty()) {
QMessageBox::warning(this, "Campo requerido", "Introduce tu contraseña.");
return;
}
if (imapHost.isEmpty()) {
QMessageBox::warning(this, "Campo requerido", "Introduce el servidor IMAP.");
return;
}
// Use defaults if ports are empty
if (imapPort.isEmpty()) imapPort = m_sslCheckbox->isChecked() ? "993" : "143";
if (smtpPort.isEmpty()) smtpPort = m_sslCheckbox->isChecked() ? "465" : "587";
if (smtpHost.isEmpty()) smtpHost = imapHost.replace("imap.", "smtp.");
if (name.isEmpty()) name = email.split("@").first();
// Show progress
m_accountCreatedOk = false;
goToPage(PageProgress);
m_progressIcon->setText("");
m_progressText->setText("Conectando al servidor…");
m_progressDetail->setText(
QString("Servidor IMAP: %1:%2\nServidor SMTP: %3:%4\nSSL: %5")
.arg(imapHost, imapPort, smtpHost, smtpPort,
m_sslCheckbox->isChecked() ? "" : "No")
);
// Simulate connection delay, then add account
QTimer::singleShot(1500, this, [this, email, name, password]() {
m_accountService->addAccount(email, "imap", password, "");
});
// Timeout for IMAP too
m_authTimeoutTimer->start(30000);
}
// ─────────────────── Account Result ───────────────────
void AccountSetupDialog::onAccountAdded(const Account &account)
{
m_authTimeoutTimer->stop();
m_accountCreatedOk = true;
qDebug() << "[AccountSetupDialog] Account created successfully:" << account.email();
// If we were on the OAuth page, move to progress first
if (m_stack->currentIndex() == PageOAuth) {
goToPage(PageProgress);
}
showSuccess(QString("¡Cuenta «%1» configurada con éxito!\n\n"
"La sincronización de correos comenzará automáticamente en segundo plano.")
.arg(account.email()));
emit accountCreated(account);
}
void AccountSetupDialog::showSuccess(const QString &message)
{
m_progressIcon->setText("");
m_progressText->setText("¡Cuenta añadida!");
m_progressDetail->setText(message);
updateNavButtons();
}
void AccountSetupDialog::showError(const QString &message)
{
m_accountCreatedOk = false;
m_progressIcon->setText("");
m_progressText->setText("Error de conexión");
m_progressDetail->setText(message);
// Allow going back
m_btnBack->setVisible(true);
m_btnCancel->setVisible(true);
m_btnNext->setVisible(false);
}
#include "accountsetupdialog.moc"
+96
View File
@@ -0,0 +1,96 @@
#ifndef ACCOUNTSETUPDIALOG_H
#define ACCOUNTSETUPDIALOG_H
#include <QDialog>
#include <QStackedWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QRadioButton>
#include <QCheckBox>
#include <QButtonGroup>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QIntValidator>
#include <QTimer>
#include "core/models/account.h"
#include "services/accountservice.h"
class AccountSetupDialog : public QDialog {
Q_OBJECT
public:
explicit AccountSetupDialog(AccountService *accountService, QWidget *parent = nullptr);
~AccountSetupDialog() override = default;
signals:
void accountCreated(const Account &account);
private slots:
void onNextClicked();
void onBackClicked();
void onCancelClicked();
void onProviderSelected(int id);
void startOAuthAuthentication();
void onAccountAdded(const Account &account);
void onAuthTimeout();
private:
void setupUI();
QWidget* createProviderPage();
QWidget* createOAuthPage();
QWidget* createImapPage();
QWidget* createProgressPage();
void goToPage(int page);
void updateNavButtons();
void showError(const QString &message);
void showSuccess(const QString &message);
void submitImapAccount();
// Services
AccountService *m_accountService;
QTimer *m_authTimeoutTimer;
// Navigation
QStackedWidget *m_stack;
QPushButton *m_btnBack;
QPushButton *m_btnNext;
QPushButton *m_btnCancel;
enum Pages {
PageProvider = 0,
PageOAuth,
PageImap,
PageProgress
};
// Page 0: Provider selection
QButtonGroup *m_providerGroup;
// Page 1: OAuth
QLineEdit *m_oauthEmailEdit;
QPushButton *m_btnOAuthStart;
QLabel *m_oauthStatusLabel;
// Page 2: IMAP manual
QLineEdit *m_imapEmailEdit;
QLineEdit *m_imapNameEdit;
QLineEdit *m_imapPasswordEdit;
QLineEdit *m_imapHostEdit;
QLineEdit *m_imapPortEdit;
QLineEdit *m_smtpHostEdit;
QLineEdit *m_smtpPortEdit;
QCheckBox *m_sslCheckbox;
// Page 3: Progress / Result
QLabel *m_progressIcon;
QLabel *m_progressText;
QLabel *m_progressDetail;
int m_selectedProvider; // 0=Gmail, 1=Outlook, 2=IMAP
bool m_accountCreatedOk;
};
#endif // ACCOUNTSETUPDIALOG_H
+30 -11
View File
@@ -60,22 +60,22 @@ void RichTextEditor::setupToolbar(QVBoxLayout *layout) {
m_toolbar->addSeparator();
// Alignment
QAction *alignLeft = m_toolbar->addAction("\xe2\x87\x94L");
QAction *alignLeft = m_toolbar->addAction("\\xe2\\x87\\x94L");
connect(alignLeft, &QAction::triggered, this, &RichTextEditor::onAlignLeft);
QAction *alignCenter = m_toolbar->addAction("\xe2\x86\x94C");
QAction *alignCenter = m_toolbar->addAction("\\xe2\\x86\\x94C");
connect(alignCenter, &QAction::triggered, this, &RichTextEditor::onAlignCenter);
QAction *alignRight = m_toolbar->addAction("\xe2\x87\x94R");
QAction *alignRight = m_toolbar->addAction("\\xe2\\x87\\x94R");
connect(alignRight, &QAction::triggered, this, &RichTextEditor::onAlignRight);
QAction *alignJustify = m_toolbar->addAction("\xe2\x87\x94J");
QAction *alignJustify = m_toolbar->addAction("\\xe2\\x87\\x94J");
connect(alignJustify, &QAction::triggered, this, &RichTextEditor::onAlignJustify);
m_toolbar->addSeparator();
// Lists
QAction *bulletAct = m_toolbar->addAction("\xe2\x80\xa2 List");
QAction *bulletAct = m_toolbar->addAction("\\xe2\\x80\\xa2 List");
connect(bulletAct, &QAction::triggered, this, &RichTextEditor::onBulletList);
QAction *numAct = m_toolbar->addAction("1. List");
@@ -84,20 +84,20 @@ void RichTextEditor::setupToolbar(QVBoxLayout *layout) {
m_toolbar->addSeparator();
// Indent / Outdent
QAction *indentAct = m_toolbar->addAction("\xe2\x86\x92 Indent");
QAction *indentAct = m_toolbar->addAction("\\xe2\\x86\\x92 Indent");
connect(indentAct, &QAction::triggered, this, &RichTextEditor::onIndent);
QAction *outdentAct = m_toolbar->addAction("\xe2\x86\x90 Outdent");
QAction *outdentAct = m_toolbar->addAction("\\xe2\\x86\\x90 Outdent");
connect(outdentAct, &QAction::triggered, this, &RichTextEditor::onOutdent);
m_toolbar->addSeparator();
// Insert image
QAction *imgAct = m_toolbar->addAction("\xf0\x9f\x96\xbc Image");
QAction *imgAct = m_toolbar->addAction("\\xf0\\x9f\\x96\\xbc Image");
connect(imgAct, &QAction::triggered, this, &RichTextEditor::onInsertImage);
// Insert table
QAction *tableAct = m_toolbar->addAction("\xe2\x96\xa4 Table");
QAction *tableAct = m_toolbar->addAction("\\xe2\\x96\\xa4 Table");
connect(tableAct, &QAction::triggered, this, &RichTextEditor::onInsertTable);
layout->addWidget(m_toolbar);
@@ -271,7 +271,7 @@ void ComposeView::setupUI() {
m_subjectField->setFont(subjectFont);
headerLayout->addWidget(m_subjectField, 1);
m_detachButton = new QPushButton("\xe2\x87\xa5 Detach");
m_detachButton = new QPushButton("\\xe2\\x87\\xa5 Detach");
m_detachButton->setToolTip("Open compose window in a separate window");
m_detachButton->setStyleSheet(
"QPushButton { background: transparent; border: 1px solid #d1d1d6; border-radius: 4px; padding: 6px 12px; color: #555; font-size: 12px; }"
@@ -483,4 +483,23 @@ void ComposeView::onDetachClicked() {
void ComposeView::setTo(const QString &to) { m_toField->setText(to); }
void ComposeView::setSubject(const QString &subject) { m_subjectField->setText(subject); }
void ComposeView::setBody(const QString &body) { m_bodyEditor->setHtml(body); }
void ComposeView::setBody(const QString &body) { m_bodyEditor->setHtml(body); }
void ComposeView::initializeComposition() {
m_toField->clear();
m_ccField->clear();
m_bccField->clear();
m_subjectField->clear();
m_bodyEditor->clear();
m_ccRow->setVisible(false);
m_bccRow->setVisible(false);
m_schedulePanel->setVisible(false);
m_toField->setFocus();
}
void ComposeView::startNewEmail(const QString &initialRecipient) {
initializeComposition();
if (!initialRecipient.isEmpty())
m_toField->setText(initialRecipient);
m_toField->setFocus();
}
#include "composeview.moc"
+47 -46
View File
@@ -1,20 +1,21 @@
#pragma once
#ifndef COMPOSEVIEW_H
#define COMPOSEVIEW_H
#include <QWidget>
#include <QLineEdit>
#include <QTextEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QDateTime>
#include <QDateTimeEdit>
#include <QMenu>
#include <QToolBar>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
#include <QFrame>
#include <QMenu>
#include <QAction>
#include <QToolButton>
#include <QDateTimeEdit>
#include <QFontComboBox>
#include <QSpinBox>
#include <QAction>
#include "models/EmailCompositionModel.h"
class RichTextEditor : public QTextEdit {
Q_OBJECT
@@ -22,7 +23,7 @@ public:
explicit RichTextEditor(QWidget *parent = nullptr);
void setupToolbar(QVBoxLayout *layout);
private slots:
public slots:
void onBold();
void onItalic();
void onUnderline();
@@ -47,57 +48,57 @@ private:
class ComposeView : public QWidget {
Q_OBJECT
public:
explicit ComposeView(QWidget *parent = nullptr);
~ComposeView() override = default;
void setTo(const QString &to);
void setSubject(const QString &subject);
void setBody(const QString &body);
signals:
void compositionFinished();
void detachRequested(QWidget *widget);
void sendRequested(const QString &to, const QString &cc, const QString &bcc,
const QString &subject, const QString &body,
const QDateTime &scheduleTime);
void discardRequested();
void detachRequested(QWidget *composeView);
public slots:
void initializeComposition();
void startNewEmail(const QString &initialRecipient);
void setTo(const QString &to);
void setSubject(const QString &subject);
void setBody(const QString &body);
private slots:
void onSendClicked();
void onScheduleClicked();
void onCcToggle();
void onBccToggle();
void onSendClicked();
void onScheduleClicked();
void onDetachClicked();
private:
void setupUI();
QLineEdit *m_toField;
QWidget *m_ccRow;
QLineEdit *m_ccField;
QWidget *m_bccRow;
QLineEdit *m_bccField;
QLineEdit *m_subjectField;
RichTextEditor *m_bodyEditor;
QToolButton *m_sendSplit;
QMenu *m_sendMenu;
QAction *m_sendNowAction;
QAction *m_scheduleAction;
QPushButton *m_discardButton;
QPushButton *m_detachButton;
QPushButton *m_ccButton;
QPushButton *m_bccButton;
QPushButton *m_hideCcButton;
QPushButton *m_hideBccButton;
QWidget *m_schedulePanel;
QDateTimeEdit *m_schedulePicker;
QPushButton *m_scheduleSendButton;
EmailCompositionModel *m_compositionModel;
// UI components
QLineEdit *m_toField = nullptr;
QLineEdit *m_subjectField = nullptr;
RichTextEditor *m_bodyEditor = nullptr;
QPushButton *m_detachButton = nullptr;
QWidget *m_ccRow = nullptr;
QWidget *m_bccRow = nullptr;
QWidget *m_schedulePanel = nullptr;
QLineEdit *m_ccField = nullptr;
QLineEdit *m_bccField = nullptr;
QPushButton *m_ccButton = nullptr;
QPushButton *m_bccButton = nullptr;
QPushButton *m_hideCcButton = nullptr;
QPushButton *m_hideBccButton = nullptr;
QDateTimeEdit *m_schedulePicker = nullptr;
QPushButton *m_scheduleSendButton = nullptr;
QPushButton *m_discardButton = nullptr;
QMenu *m_sendMenu = nullptr;
QAction *m_sendNowAction = nullptr;
QAction *m_scheduleAction = nullptr;
QToolButton *m_sendSplit = nullptr;
bool m_ccVisible = false;
bool m_bccVisible = false;
};
};
#endif // COMPOSEVIEW_H
+15 -5
View File
@@ -2,6 +2,7 @@
#include "core/models/account.h"
#include "core/mailitem.h"
#include "db/dao/mailitemdao.h"
#include "ui/accountsetupdialog.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFrame>
@@ -9,7 +10,7 @@
#include <QLabel>
MainMainWindow::MainMainWindow(QWidget *parent)
: QMainWindow(parent), m_currentFolderId(-1)
: QMainWindow(parent), m_currentFolderId(-1), m_currentMailId(-1)
{
setupUI();
connectModels();
@@ -96,7 +97,8 @@ void MainMainWindow::setupUI() {
// Page 2: Settings
m_settingsView = new SettingsView();
connect(m_settingsView, &SettingsView::accountAddRequested, [this]() {
statusBar()->showMessage("Account setup dialog would open here", 3000);
AccountSetupDialog dlg(m_accountService, this);
dlg.exec();
});
connect(m_settingsView, &SettingsView::themeChanged, [this](const QString &theme) {
statusBar()->showMessage(QString("Theme changed to: %1 (restart may be required)").arg(theme), 3000);
@@ -174,9 +176,8 @@ void MainMainWindow::setupMailPage() {
m_emailViewer->setMinimumWidth(350);
connect(m_emailViewer, &ReaderView::replyRequested, this, &MainMainWindow::onReaderReplyRequested);
connect(m_emailViewer, &ReaderView::detachRequested, this, [this]() {
std::optional<MailItem> currentItem = MailItemDao::findById(m_emailModel->getCurrentMailId());
if (currentItem) {
openMailInIndependentWindow(currentItem->id());
if (m_currentMailId >= 0) {
openMailInIndependentWindow(m_currentMailId);
}
});
m_folderSplitter->addWidget(m_emailViewer);
@@ -227,6 +228,7 @@ void MainMainWindow::onFolderSelected(const QModelIndex &index) {
}
void MainMainWindow::onEmailSelected(int mailId) {
m_currentMailId = mailId;
std::optional<MailItem> item = MailItemDao::findById(mailId);
if (!item.has_value()) {
m_emailViewer->setMailItem(nullptr);
@@ -282,6 +284,7 @@ void MainMainWindow::createToolBar() {
QAction *newMsgAction = m_toolBar->addAction("✉ New Message");
m_toolBar->addSeparator();
QAction *syncAction = m_toolBar->addAction("⟳ Sync/Refresh");
QAction *openWinAction = m_toolBar->addAction("↗ Abrir en ventana");
QAction *deleteAction = m_toolBar->addAction("🗑 Delete");
connect(newMsgAction, &QAction::triggered, this, &MainMainWindow::onNewMessage);
@@ -291,6 +294,13 @@ void MainMainWindow::createToolBar() {
statusBar()->showMessage("Refreshed", 2000);
}
});
connect(openWinAction, &QAction::triggered, [this]() {
if (m_currentMailId >= 0) {
openMailInIndependentWindow(m_currentMailId);
} else {
statusBar()->showMessage("Selecciona un correo primero para abrirlo en una ventana", 3000);
}
});
connect(deleteAction, &QAction::triggered, [this]() {
statusBar()->showMessage("Delete would be implemented here", 3000);
});
+1
View File
@@ -77,4 +77,5 @@ private:
QToolBar *m_toolBar;
int m_currentFolderId;
int m_currentMailId;
};
+2 -2
View File
@@ -41,8 +41,8 @@ void ReaderView::setupUI() {
m_deleteButton = new QPushButton("Delete");
m_deleteButton->setStyleSheet("color: red;");
QPushButton *m_detachButton = new QPushButton("独立 (Independent)");
m_detachButton->setToolTip("Open in separate window");
QPushButton *m_detachButton = new QPushButton("↗ Abrir en ventana");
m_detachButton->setToolTip("Abrir este correo en una ventana independiente");
actionsLayout->addWidget(m_replyButton);
actionsLayout->addWidget(m_forwardButton);