2026-06-23 01:34:13 +02:00
|
|
|
|
#include "ui/accountsetupdialog.h"
|
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
|
|
#include <QScrollArea>
|
|
|
|
|
|
#include <QFrame>
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
#include <QRegularExpression>
|
|
|
|
|
|
#include <QRegularExpressionValidator>
|
2026-07-05 10:45:44 +02:00
|
|
|
|
#include <QIntValidator>
|
|
|
|
|
|
#include <QTimer>
|
2026-06-23 01:34:13 +02:00
|
|
|
|
|
|
|
|
|
|
// ─────────────────────── Constructor ───────────────────────
|
|
|
|
|
|
AccountSetupDialog::AccountSetupDialog(AccountService *accountService, QWidget *parent)
|
|
|
|
|
|
: QDialog(parent)
|
|
|
|
|
|
, m_accountService(accountService)
|
|
|
|
|
|
, m_selectedProvider(0)
|
|
|
|
|
|
, m_accountCreatedOk(false)
|
2026-07-05 10:45:44 +02:00
|
|
|
|
, m_editingAccountId(-1)
|
|
|
|
|
|
, m_isEditing(false)
|
2026-06-23 01:34:13 +02:00
|
|
|
|
{
|
|
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
|
// ─────────────────────── Public API ───────────────────────
|
|
|
|
|
|
void AccountSetupDialog::loadAccountForEditing(const Account &account)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Only support editing IMAP accounts for simplicity
|
|
|
|
|
|
if (account.type() != AccountType::IMAP) {
|
|
|
|
|
|
QMessageBox::information(this, tr("Edit Account"),
|
|
|
|
|
|
tr("Editing of OAuth (Gmail/Outlook) accounts is not supported in this version.\n"
|
|
|
|
|
|
"You can add a new account instead."));
|
|
|
|
|
|
m_isEditing = false;
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-06-23 01:34:13 +02:00
|
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
|
m_isEditing = true;
|
|
|
|
|
|
m_editingAccountId = account.id();
|
|
|
|
|
|
|
|
|
|
|
|
// Set window title
|
|
|
|
|
|
setWindowTitle(tr("Edit Email Account – Wino Mail"));
|
|
|
|
|
|
|
|
|
|
|
|
// Fill IMAP fields
|
|
|
|
|
|
m_imapEmailEdit->setText(account.email());
|
|
|
|
|
|
m_imapNameEdit->setText(account.displayName());
|
|
|
|
|
|
|
|
|
|
|
|
// Password field left blank for security; user must re-enter
|
|
|
|
|
|
m_imapPasswordEdit->clear();
|
|
|
|
|
|
|
|
|
|
|
|
const Account::ConnectionSettings &settings = account.connectionSettings();
|
|
|
|
|
|
m_imapHostEdit->setText(settings.incomingHost);
|
|
|
|
|
|
m_imapPortEdit->setText(QString::number(settings.incomingPort));
|
|
|
|
|
|
m_smtpHostEdit->setText(settings.outgoingHost);
|
|
|
|
|
|
m_smtpPortEdit->setText(QString::number(settings.outgoingPort));
|
|
|
|
|
|
m_sslCheckbox->setChecked(settings.incomingSsl); // assuming same for SMTP
|
|
|
|
|
|
|
|
|
|
|
|
// Switch to IMAP page
|
|
|
|
|
|
m_selectedProvider = 2; // IMAP
|
|
|
|
|
|
goToPage(PageImap);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ─────────────────────── UI Setup ───────────────────────
|
2026-06-23 01:34:13 +02:00
|
|
|
|
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(
|
2026-07-05 10:45:44 +02:00
|
|
|
|
"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"
|
2026-06-23 01:34:13 +02:00
|
|
|
|
" 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:
|
2026-07-05 10:45:44 +02:00
|
|
|
|
m_btnNext->setText(m_isEditing ? "Guardar cambios" : "Conectar");
|
2026-06-23 01:34:13 +02:00
|
|
|
|
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();
|
|
|
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
|
// Create account with connection settings
|
|
|
|
|
|
Account account;
|
|
|
|
|
|
account.setEmail(email);
|
|
|
|
|
|
account.setDisplayName(name);
|
|
|
|
|
|
account.setType(AccountType::IMAP);
|
|
|
|
|
|
|
|
|
|
|
|
Account::ConnectionSettings settings;
|
|
|
|
|
|
settings.type = "imap";
|
|
|
|
|
|
settings.incomingHost = imapHost;
|
|
|
|
|
|
settings.incomingPort = imapPort.toInt();
|
|
|
|
|
|
settings.incomingSsl = m_sslCheckbox->isChecked();
|
|
|
|
|
|
settings.outgoingHost = smtpHost;
|
|
|
|
|
|
settings.outgoingPort = smtpPort.toInt();
|
|
|
|
|
|
settings.outgoingSsl = m_sslCheckbox->isChecked();
|
|
|
|
|
|
settings.username = email;
|
|
|
|
|
|
settings.password = password;
|
|
|
|
|
|
settings.authMethod = "plain";
|
|
|
|
|
|
|
|
|
|
|
|
account.setConnectionSettings(settings);
|
|
|
|
|
|
|
2026-06-23 01:34:13 +02:00
|
|
|
|
// Show progress
|
|
|
|
|
|
m_accountCreatedOk = false;
|
|
|
|
|
|
goToPage(PageProgress);
|
|
|
|
|
|
m_progressIcon->setText("⏳");
|
2026-07-05 10:45:44 +02:00
|
|
|
|
m_progressText->setText("Conectando al servidor...");
|
2026-06-23 01:34:13 +02:00
|
|
|
|
m_progressDetail->setText(
|
2026-07-05 10:45:44 +02:00
|
|
|
|
QString("Servidor IMAP: %1:%2\\nServidor SMTP: %3:%4\\nSSL: %5")
|
2026-06-23 01:34:13 +02:00
|
|
|
|
.arg(imapHost, imapPort, smtpHost, smtpPort,
|
|
|
|
|
|
m_sslCheckbox->isChecked() ? "Sí" : "No")
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2026-07-06 16:25:43 +02:00
|
|
|
|
// Disable UI during connection attempt
|
|
|
|
|
|
m_btnBack->setEnabled(false);
|
|
|
|
|
|
m_btnNext->setEnabled(false);
|
|
|
|
|
|
m_btnCancel->setEnabled(false);
|
|
|
|
|
|
QString errorMsg;
|
|
|
|
|
|
bool success = m_accountService->testConnection(account.connectionSettings(), errorMsg);
|
|
|
|
|
|
if (success) {
|
|
|
|
|
|
if (m_isEditing) {
|
|
|
|
|
|
account.setId(m_editingAccountId);
|
|
|
|
|
|
m_accountService->updateAccount(account);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
m_accountService->addAccount(account);
|
|
|
|
|
|
}
|
|
|
|
|
|
m_btnCancel->setEnabled(true);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
QMessageBox::warning(this, tr("Connection failed"), tr("Could not connect to IMAP server: %1").arg(errorMsg));
|
|
|
|
|
|
// Re-enable UI
|
|
|
|
|
|
m_btnBack->setEnabled(true);
|
|
|
|
|
|
m_btnNext->setEnabled(true);
|
|
|
|
|
|
m_btnCancel->setEnabled(true);
|
|
|
|
|
|
}
|
2026-06-23 01:34:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ─────────────────── Account Result ───────────────────
|
|
|
|
|
|
void AccountSetupDialog::onAccountAdded(const Account &account)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_authTimeoutTimer->stop();
|
|
|
|
|
|
m_accountCreatedOk = true;
|
|
|
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
|
qDebug() << "[AccountSetupDialog] Account" << (m_isEditing ? "updated" : "created") << "successfully:" << account.email();
|
2026-06-23 01:34:13 +02:00
|
|
|
|
|
|
|
|
|
|
// If we were on the OAuth page, move to progress first
|
|
|
|
|
|
if (m_stack->currentIndex() == PageOAuth) {
|
|
|
|
|
|
goToPage(PageProgress);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
|
showSuccess(QString(m_isEditing ? "¡Cuenta «%1» actualizada con éxito!\\n\\n"
|
|
|
|
|
|
"Los cambios se aplicarán inmediatamente."
|
|
|
|
|
|
: "¡Cuenta «%1» configurada con éxito!\\n\\n"
|
|
|
|
|
|
"La sincronización de correos comenzará automáticamente en segundo plano.")
|
2026-06-23 01:34:13 +02:00
|
|
|
|
.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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-05 10:45:44 +02:00
|
|
|
|
#include "accountsetupdialog.moc"
|