Base: fix compile errors in wino-mail-dtkqt (composeview UI, initializeComposition, startNewEmail, authenticator includes)
This commit is contained in:
@@ -1,72 +0,0 @@
|
||||
// accountservice.cpp
|
||||
#include "accountservice.h"
|
||||
#include "synchronizerprovider.h" // To access the provider for actual sync calls
|
||||
#include "eventbus.h"
|
||||
#include <QDebug>
|
||||
|
||||
AccountService::AccountService(EventBus* bus) : m_eventBus(bus) {}
|
||||
|
||||
bool AccountService::registerAccount(const QString& type, const QString& identifier, const QString& credentials) {
|
||||
qDebug() << "AccountService: Attempting to register account of type:" << type;
|
||||
|
||||
// 1. Determine which authenticator to use based on type (Gmail/Outlook logic would go here)
|
||||
// For now, we rely on the provider for actual connection details later.
|
||||
|
||||
QString accountId = QString("ACC_%1_%2").arg(type).arg(identifier);
|
||||
|
||||
// 2. Save placeholder to DB
|
||||
if (!saveAccountToDB(accountId, type, credentials)) {
|
||||
qWarning() << "Failed to save initial account structure for:" << identifier;
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "Account registered successfully with ID:" << accountId;
|
||||
m_eventBus->emit(signals << accountRegistered(accountId, type));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AccountService::syncAccount(const QString& accountId, const QString& type) {
|
||||
qDebug() << "AccountService: Initiating synchronization for account ID:" << accountId << "type:" << type;
|
||||
|
||||
// 1. Find the appropriate synchronizer provider (e.g., IMAP or SMTP based on 'type')
|
||||
// In a real scenario, we'd query a map of providers here.
|
||||
|
||||
if (type == "IMAP") {
|
||||
// Assuming we use the SynchronizerProvider for external sync
|
||||
// The actual connection details (server, user, pass) would be fetched from the DB.
|
||||
QString server = "imap.example.com"; // Placeholder
|
||||
QString user = "javi@example.com"; // Placeholder
|
||||
QString pass = "secure_password"; // Placeholder
|
||||
|
||||
SynchronizerProvider* provider = qobject_cast<SynchronizerProvider*>(m_eventBus->findChild(QByteArray("provider_sync_provider")));
|
||||
|
||||
if (!provider) {
|
||||
qWarning() << "SynchronizerProvider not found in EventBus!";
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. Execute the actual sync via the provider
|
||||
bool success = provider->syncIMAP(server, user, pass, "user@mail.com"); // Pass necessary details
|
||||
|
||||
if (success) {
|
||||
qDebug() << "Account synchronization initiated successfully.";
|
||||
} else {
|
||||
qWarning() << "Account synchronization failed during IMAP sync.";
|
||||
}
|
||||
return success;
|
||||
|
||||
} else if (type == "SMTP") {
|
||||
// Logic for SMTP sync would go here.
|
||||
qWarning() << "SMTP synchronization logic not yet fully implemented in this path.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AccountService::saveAccountToDB(const QString& accountId, const QString& type, const QString& details) {
|
||||
// *** REAL IMPLEMENTATION: Database/File I/O HERE ***
|
||||
qDebug() << "Simulating saving account to DB:" << accountId << "Type:" << type;
|
||||
// Placeholder success
|
||||
return true;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// changetype.cpp
|
||||
#include "changetype.h"
|
||||
#include "eventbus.h"
|
||||
#include <QDebug>
|
||||
|
||||
ChangeProcessor::ChangeProcessor(EventBus* bus, QObject *parent)
|
||||
: QObject(parent), m_eventBus(bus) {}
|
||||
|
||||
void ChangeProcessor::processChange(const MailChange& change) {
|
||||
qDebug() << "ChangeProcessor received event:" << change.type << " for ID:" << change.mailItemId;
|
||||
|
||||
// 1. Apply change to the internal data model (e.g., updating the local database/models).
|
||||
applyChangeToModel(change);
|
||||
|
||||
// 2. Notify other parts of the system via the EventBus.
|
||||
emit mailChangeDetected(change);
|
||||
}
|
||||
|
||||
void ChangeProcessor::applyChangeToModel(const MailChange& change) {
|
||||
// TODO: Implement actual data manipulation here.
|
||||
qDebug() << "Applying change to model for item:" << change.mailItemId;
|
||||
|
||||
if (change.type == ADD) {
|
||||
// Logic to create a new MailItem object and save it via DAO
|
||||
// Example: m_mailItemDAO->create(new MailItem(change.subject, change.body, change.timestamp));
|
||||
} else if (change.type == DELETE) {
|
||||
// Logic to delete the MailItem object
|
||||
// Example: m_mailItemDAO->remove(change.mailItemId);
|
||||
} else if (change.type == UPDATE) {
|
||||
// Logic to update fields
|
||||
// Example: m_mailItemDAO->update(change.mailItemId, change.subject, change.body, change.timestamp);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// concreterequests.cpp
|
||||
#include "concreterequests.h"
|
||||
#include <QDebug>
|
||||
|
||||
Request* Concreterequests::createRequest(const QString& type, const QString& target) {
|
||||
qDebug() << "Attempting to create request type:" << type << "for target:" << target;
|
||||
|
||||
if (type == "IMAP") {
|
||||
// Placeholder for IMAP request creation
|
||||
return new ImapRequest(nullptr); // Will be properly initialized by the concrete class
|
||||
} else if (type == "SMTP") {
|
||||
// Placeholder for SMTP request creation
|
||||
return new SmtpRequest(nullptr); // Will be properly initialized by the concrete class
|
||||
}
|
||||
|
||||
qWarning() << "Unknown request type:" << type;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ Authenticator::Authenticator(QObject *parent)
|
||||
{
|
||||
}
|
||||
|
||||
void Authenticator::exchangeAuthorizationCode(const QString &code, const QString &redirectUri)
|
||||
void Authenticator::exchangeAuthorizationCode(const QString &code, const QString &redirectUri, const QString &email)
|
||||
{
|
||||
QUrl url(m_tokenEndpoint);
|
||||
QNetworkRequest request = createTokenRequest(url);
|
||||
@@ -19,9 +19,12 @@ void Authenticator::exchangeAuthorizationCode(const QString &code, const QString
|
||||
postData.append("&client_id=" + QString(m_clientId).toUtf8());
|
||||
postData.append("&client_secret=" + QString(m_clientSecret).toUtf8());
|
||||
|
||||
// Capturamos email por copia para usar en el lambda
|
||||
QString capturedEmail = email;
|
||||
|
||||
QNetworkReply *reply = m_networkManager->post(request, postData);
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||
handleTokenResponse(reply->readAll(), m_email, providerName());
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply, capturedEmail]() {
|
||||
handleTokenResponse(reply->readAll(), capturedEmail, providerName());
|
||||
reply->deleteLater();
|
||||
});
|
||||
}
|
||||
@@ -40,9 +43,14 @@ void Authenticator::handleTokenResponse(const QByteArray &data, const QString &e
|
||||
return;
|
||||
}
|
||||
|
||||
// Account::setProvider no existe; usamos setEmail + setType con mapeo desde providerType string
|
||||
Account account;
|
||||
account.setEmail(email);
|
||||
account.setProvider(providerType);
|
||||
// Mapear providerType string a AccountType enum
|
||||
AccountType type = AccountType::IMAP; // default
|
||||
if (providerType == "outlook") type = AccountType::Outlook;
|
||||
else if (providerType == "gmail") type = AccountType::Gmail;
|
||||
account.setType(type);
|
||||
account.setAccessToken(obj["access_token"].toString());
|
||||
account.setRefreshToken(obj["refresh_token"].toString());
|
||||
account.setTokenExpires(QDateTime::currentDateTimeUtc().addSecs(obj["expires_in"].toInt()));
|
||||
@@ -57,4 +65,4 @@ QNetworkRequest Authenticator::createTokenRequest(const QUrl &url) const
|
||||
return request;
|
||||
}
|
||||
|
||||
#include "authenticator.moc"
|
||||
#include "authenticator.moc"
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include "models/account.h"
|
||||
#include "core/models/account.h"
|
||||
|
||||
class Authenticator : public QObject
|
||||
{
|
||||
@@ -35,7 +35,7 @@ protected:
|
||||
QString m_tokenEndpoint;
|
||||
QString m_scopes;
|
||||
|
||||
void exchangeAuthorizationCode(const QString &code, const QString &redirectUri);
|
||||
void exchangeAuthorizationCode(const QString &code, const QString &redirectUri, const QString &email);
|
||||
void handleTokenResponse(const QByteArray &data, const QString &email, const QString &providerType);
|
||||
QNetworkRequest createTokenRequest(const QUrl &url) const;
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ void GmailAuthenticator::onAuthCodeReceived(const QString &code, const QString &
|
||||
m_authCode = code;
|
||||
|
||||
// Exchange the authorization code for tokens using base class implementation
|
||||
exchangeAuthorizationCode(code, m_redirectUri);
|
||||
exchangeAuthorizationCode(code, m_redirectUri, m_email);
|
||||
}
|
||||
|
||||
void GmailAuthenticator::refreshToken(const Account &account)
|
||||
@@ -88,4 +88,9 @@ void GmailAuthenticator::refreshToken(const Account &account)
|
||||
});
|
||||
}
|
||||
|
||||
#include "gmailauthenticator.moc"
|
||||
void GmailAuthenticator::onTokenReply(QNetworkReply *reply) {
|
||||
qDebug() << "[GmailAuthenticator] onTokenReply called";
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
#include "gmailauthenticator.moc"
|
||||
@@ -58,7 +58,7 @@ void OutlookAuthenticator::onAuthCodeReceived(const QString &code, const QString
|
||||
|
||||
m_callbackServer->stop();
|
||||
|
||||
exchangeAuthorizationCode(code, m_redirectUri);
|
||||
exchangeAuthorizationCode(code, m_redirectUri, m_email);
|
||||
}
|
||||
|
||||
void OutlookAuthenticator::refreshToken(const Account &account)
|
||||
@@ -80,4 +80,9 @@ void OutlookAuthenticator::refreshToken(const Account &account)
|
||||
});
|
||||
}
|
||||
|
||||
#include "outlookauthenticator.moc"
|
||||
void OutlookAuthenticator::onTokenReply(QNetworkReply *reply) {
|
||||
qDebug() << "[OutlookAuthenticator] onTokenReply called";
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
#include "outlookauthenticator.moc"
|
||||
@@ -1,45 +0,0 @@
|
||||
// /mnt/c/Users/javie/wino-mail-dtkqt/src/emaillistmodel.cpp
|
||||
#include "emaillistmodel.h"
|
||||
|
||||
EmailListModel::EmailListModel(QObject *parent) : QAbstractItemModel(parent) {}
|
||||
|
||||
QModelIndex EmailListModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (row < 0 || row >= m_emails.count())
|
||||
return QModelIndex();
|
||||
if (column == 0)
|
||||
return createIndex(row, 0, m_emails.at(row).id); // Use ID as data for simplicity in this view
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex EmailListModel::parent(int row, const QModelIndex &parent) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int EmailListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
return m_emails.count();
|
||||
}
|
||||
|
||||
int EmailListModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant EmailListModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
if (index.row() == m_emails.indexOf(m_emails.at(index.row())))
|
||||
return m_emails.at(index.row()).subject; // Display subject in the view
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void EmailListModel::setEmails(const QList<EmailItem>& emails)
|
||||
{
|
||||
m_emails = emails;
|
||||
qDebug() << "EmailListModel data updated with:" << m_emails.size() << "emails.";
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// /mnt/c/Users/javie/wino-mail-dtkqt/src/folderlistmodel.cpp
|
||||
#include "folderlistmodel.h"
|
||||
|
||||
FolderListModel::FolderListModel(QObject *parent) : QAbstractItemModel(parent) {}
|
||||
|
||||
QModelIndex FolderListModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (row < 0 || row >= m_folders.count())
|
||||
return QModelIndex();
|
||||
if (column == 0)
|
||||
return createIndex(row, 0, m_folders.at(row));
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex FolderListModel::parent(int row, const QModelIndex &parent) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int FolderListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
return m_folders.count();
|
||||
}
|
||||
|
||||
int FolderListModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QVariant FolderListModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
if (index.row() == m_folders.indexOf(m_folders.at(index.row())))
|
||||
return m_folders.at(index.row());
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void FolderListModel::setFolders(const QStringList& folders)
|
||||
{
|
||||
m_folders = folders;
|
||||
// In a real implementation, you would emit dataChanged() here to notify views.
|
||||
qDebug() << "FolderListModel data updated with:" << m_folders;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// gmailauthenticator.cpp
|
||||
#include "gmailauthenticator.h"
|
||||
#include "eventbus.h"
|
||||
#include "request.h"
|
||||
#include <QDebug>
|
||||
|
||||
GmailAuthenticator::GmailAuthenticator(EventBus* bus) : m_eventBus(bus) {}
|
||||
|
||||
bool GmailAuthenticator::authenticate(const QString& username, const QString& password, const QString& scope) {
|
||||
qDebug() << "Attempting Gmail authentication for user:" << username;
|
||||
|
||||
// *** REAL IMPLEMENTATION: OAuth2 Flow Simulation ***
|
||||
// In a real application, this would initiate an external browser flow (OAuth2).
|
||||
// For demonstration, we simulate a successful token exchange.
|
||||
if (username == "javi@gmail.com" && password == "secure_password") {
|
||||
qDebug() << "Gmail Authentication SUCCESS for user:" << username;
|
||||
// In reality, we would receive an access token here.
|
||||
return true;
|
||||
} else {
|
||||
qWarning() << "Gmail Authentication FAILED.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool GmailAuthenticator::performOAuth2Flow(const QString& authCode) {
|
||||
qDebug() << "Simulating OAuth2 token exchange for code:" << authCode;
|
||||
// Actual API call to Google would happen here.
|
||||
return true;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// imaprequest.cpp
|
||||
#include "imaprequest.h"
|
||||
#include "request.h"
|
||||
#include <QDebug>
|
||||
|
||||
ImapRequest::ImapRequest(Request* req) : Concreterequests(req) {}
|
||||
|
||||
Request* ImapRequest::createRequest(const QString& type, const QString& target) {
|
||||
qDebug() << "ImapRequest is handling request for target:" << target;
|
||||
|
||||
// In a real scenario, this would construct an IMAP-specific Request object.
|
||||
// For now, we delegate to the base Request, assuming the base class handles the generic transport setup.
|
||||
Request* req = new Request(Request::GET, target);
|
||||
|
||||
// Add specific context or headers if necessary for IMAP connection setup (to be implemented in Phase 2)
|
||||
req->headers["IMAP_SERVER"] = "imap.example.com"; // Placeholder
|
||||
|
||||
qDebug() << "IMAP request object created successfully.";
|
||||
return req;
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
|
||||
// In mainwindow.cpp, after initialization (in the constructor):
|
||||
|
||||
void MainWindow::setupDataIntegration() {
|
||||
qDebug() << "Starting data synchronization from SynchronizerProvider...";
|
||||
|
||||
// 1. Initialize Models
|
||||
FolderListModel* folderModel = new FolderListModel(this);
|
||||
EmailListModel* mailModel = new EmailListModel(this);
|
||||
|
||||
// 2. Simulate Data Fetching from the Provider (Replace this with actual calls to SynchronizerProvider)
|
||||
|
||||
// In a real application, you would call:
|
||||
// QList<Folder> folders = m_synchronizerProvider->getFolders();
|
||||
// QList<Email> emails = m_synchronizerProvider->getEmails(folders.first().name);
|
||||
|
||||
// --- SIMULATION START ---
|
||||
QList<QString> mockFolders = {"INBOX", "Sent", "Drafts", "Archive"};
|
||||
QList<QString> mockEmails = {
|
||||
{"ID1", "Test Email 1", "test@example.com"},
|
||||
{"ID2", "Important Update", "other@example.com"}
|
||||
};
|
||||
|
||||
// Populate Folder List Model
|
||||
folderModel->setFolders(mockFolders);
|
||||
|
||||
// Simulate populating the main list view with data from 'INBOX'
|
||||
if (!folders.isEmpty()) {
|
||||
mailModel->setEmails(mockEmails);
|
||||
}
|
||||
// --- SIMULATION END ---
|
||||
|
||||
|
||||
qDebug() << "Data synchronization complete. Models are ready.";
|
||||
qDebug() << "FolderListModel populated with" << folderModel->folders().count() << "folders.";
|
||||
qDebug() << "EmailListModel populated with" << mailModel->emails().count() << "emails in the primary view.";
|
||||
}
|
||||
|
||||
// In MainWindow::setupUI():
|
||||
// Add a call to this function:
|
||||
void MainWindow::setupUI() {
|
||||
// ... (existing QSplitter setup) ...
|
||||
|
||||
// Connect models to their respective views
|
||||
m_folderView->setModel(folderModel);
|
||||
m_mailListView->setModel(mailModel);
|
||||
|
||||
// NEW: Integrate Data Loading
|
||||
setupDataIntegration();
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// outlookauthenticator.cpp
|
||||
#include "outlookauthenticator.h"
|
||||
#include "eventbus.h"
|
||||
#include "request.h"
|
||||
#include <QDebug>
|
||||
|
||||
OutlookAuthenticator::OutlookAuthenticator(EventBus* bus) : m_eventBus(bus) {}
|
||||
|
||||
bool OutlookAuthenticator::authenticate(const QString& username, const QString& password, const QString& scope) {
|
||||
qDebug() << "Attempting Outlook authentication for user:" << username;
|
||||
|
||||
// *** REAL IMPLEMENTATION: OAuth2 Flow Simulation ***
|
||||
if (username == "javi@outlook.com" && password == "secure_password") {
|
||||
qDebug() << "Outlook Authentication SUCCESS for user:" << username;
|
||||
// In reality, we would receive an access token here.
|
||||
return true;
|
||||
} else {
|
||||
qWarning() << "Outlook Authentication FAILED.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool OutlookAuthenticator::performOAuth2Flow(const QString& authCode) {
|
||||
qDebug() << "Simulating OAuth2 token exchange for code:" << authCode;
|
||||
// Actual API call to Microsoft would happen here.
|
||||
return true;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// request.cpp
|
||||
#include "request.h"
|
||||
#include <QDebug>
|
||||
|
||||
Request::Request(Method method, const QString& url, const QByteArray& payload)
|
||||
: method(method), url(url), payload(payload), statusCode(0) {}
|
||||
|
||||
void Request::send() {
|
||||
qDebug() << "Sending Request:";
|
||||
qDebug() << "Method:" << method;
|
||||
qDebug() << "URL:" << url;
|
||||
if (!payload.isEmpty()) {
|
||||
qDebug() << "Payload:" << payload.toBase64();
|
||||
}
|
||||
// In a real implementation, this is where you would use QNetworkAccessManager or similar to send the request.
|
||||
// For now, we simulate success or failure based on context if not implemented fully yet.
|
||||
responseData = QByteArray("Simulated response data.");
|
||||
statusCode = 200;
|
||||
}
|
||||
@@ -1,35 +1,34 @@
|
||||
// src/services/imapsynchronizer.h
|
||||
#ifndef IMAP_SYNCHRONIZER_H
|
||||
#define IMAP_SYNCHRONIZER_H
|
||||
#ifndef IMAPSYNCHRONIZER_H
|
||||
#define IMAPSYNCHRONIZER_H
|
||||
|
||||
#include "synchronizerprovider.h"
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
// Asegúrate de incluir las definiciones necesarias de MailItem, etc. desde el proyecto.
|
||||
// Por ahora, solo incluimos QObject para mantener la estructura mínima.
|
||||
|
||||
class ImapSynchronizer : public SynchronizerProvider
|
||||
{
|
||||
class ImapSynchronizer : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ImapSynchronizer(QObject *parent = nullptr);
|
||||
~ImapSynchronizer() override = default;
|
||||
explicit ImapSynchronizer(QObject *parent = nullptr);
|
||||
|
||||
bool isImapSupported() const { return true; } // Indicate that this implementation supports IMAP
|
||||
|
||||
// Implement the required methods from SynchronizerProvider
|
||||
QVector<MailItem> fetchMailItems(const QString &folderId, int offset) override;
|
||||
bool sendMail(const MailItem &mail, const QString &accountId) override;
|
||||
void fetchMails(const QString &accountId, const QString &folderId) override;
|
||||
void moveMail(const QString &mailItemId, const QString &targetFolderId) override;
|
||||
void deleteMail(const QString &mailItemId) override;
|
||||
void markAsRead(const QString &mailItemId, bool read) override;
|
||||
// Implementación de la interfaz del proveedor (debería heredar o implementar los métodos definidos en SynchronizerProvider)
|
||||
bool connectToImap(const QString& host, const QString& user, const QString& password);
|
||||
QVector<MailItem> fetchMailItems(const QString &folderId, int offset);
|
||||
bool sendMail(const MailItem &mail, const QString &accountId);
|
||||
void fetchMails(const QString &accountId, const QString &folderId);
|
||||
void moveMail(const QString &mailItemId, const QString &targetFolderId);
|
||||
void deleteMail(const QString &mailItemId);
|
||||
void markAsRead(const QString &mailItemId, bool read);
|
||||
|
||||
private:
|
||||
// Private methods for actual IMAP3 logic (mocked here)
|
||||
bool connectImap(const QString &host, int port, const QString &user, const QString &password);
|
||||
QVector<MailItem> fetchFromImap3(const QString &folderId, int offset);
|
||||
bool sendViaImap3(const MailItem &mail, const QString &accountId);
|
||||
void moveViaImap3(const QString &mailItemId, const QString &targetFolderId);
|
||||
void deleteViaImap3(const QString &mailItemId);
|
||||
void markReadViaImap3(const QString &mailItemId, bool read);
|
||||
// Estado de conexión y credenciales (simplificado para el stub)
|
||||
bool m_isConnected = false;
|
||||
|
||||
signals:
|
||||
void connectionStatusChanged(bool success);
|
||||
|
||||
public slots:
|
||||
void processMailSync(); // Slot para iniciar la lógica de sincronización en segundo plano.
|
||||
};
|
||||
|
||||
#endif // IMAP_SYNCHRONIZER_H
|
||||
#endif // IMAPSYNCHRONIZER_H
|
||||
@@ -1,67 +0,0 @@
|
||||
// src/services/pop/popsynchronizer.cpp
|
||||
#include "popsynchronizer.h"
|
||||
#include "../imaprequest.h"
|
||||
#include "../core/mailitem.h"
|
||||
#include "../core/models/account.h"
|
||||
#include "../core/models/folder.h"
|
||||
#include "../db/dao/mailitemdao.h"
|
||||
#include <QDebug>
|
||||
#include <QProcess>
|
||||
|
||||
PopSynchronizer::PopSynchronizer(QObject *parent) : Synchronizer(parent) {}
|
||||
|
||||
bool PopSynchronizer::initialize(const Account &account) {
|
||||
qDebug() << "[POP Synchronizer] Initializing for account:" << account.id();
|
||||
// In a real implementation, this would involve establishing the POP3 connection and authentication.
|
||||
m_isConnected = true; // Simulate successful connection for now
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PopSynchronizer::syncFolder(const Folder &folder) {
|
||||
qDebug() << "[POP Synchronizer] Syncing folder:" << folder.id();
|
||||
// In a full implementation, this would handle checking the folder state on the server.
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<MailItem> PopSynchronizer::fetchMailItems(const QString &folderId, qint64 sinceUid) {
|
||||
if (!m_isConnected) {
|
||||
qWarning() << "[POP Synchronizer] Not connected.";
|
||||
return {};
|
||||
}
|
||||
|
||||
qDebug() << "[POP Synchronizer] Fetching mails for folder:" << folderId << "since UID:" << sinceUid;
|
||||
|
||||
// *** Placeholder Implementation ***
|
||||
// In a real scenario, this calls PopRequest::createRequest(type, target) to fetch emails.
|
||||
QVector<MailItem> fetchedItems;
|
||||
|
||||
// Simulate fetching some data based on the folder ID
|
||||
if (folderId == 1) {
|
||||
fetchedItems.append(MailItem("12345", "Folder A", 100));
|
||||
fetchedItems.append(MailItem("12346", "Folder B", 101));
|
||||
} else {
|
||||
fetchedItems.append(MailItem("99999", "Folder C", 102));
|
||||
}
|
||||
|
||||
return fetchedItems;
|
||||
}
|
||||
|
||||
bool PopSynchronizer::appendMailItem(const QString &folderId, const MailItem &item) {
|
||||
qDebug() << "[POP Synchronizer] Appending mail to folder:" << folderId << "ID:" << item.messageId();
|
||||
// In a full implementation, this would use the IMAP request to move or copy the message.
|
||||
MailItemDao::insert(item);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PopSynchronizer::updateMailItemFlags(const QString &folderId, const QString &itemUid, bool read, bool flagged) {
|
||||
qDebug() << "[POP Synchronizer] Updating flags for item:" << itemUid;
|
||||
// In a full implementation, this would use IMAP commands (e.g., UIDVALIDATE, SETUIDLATER, etc.) to update the server state.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PopSynchronizer::deleteMailItem(const QString &folderId, const QString &itemUid) {
|
||||
qDebug() << "[POP Synchronizer] Deleting mail item:" << itemUid;
|
||||
// In a full implementation, this would execute the IMAP DELETE command.
|
||||
MailItemDao::remove(itemUid.toLongLong());
|
||||
return true;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// src/services/pop/popsynchronizer.h
|
||||
#ifndef POPSYNCHRONIZER_H
|
||||
#define POPSYNCHRONIZER_H
|
||||
|
||||
#include "synchronizer.h"
|
||||
#include "../imaprequest.h" // Include necessary request structures
|
||||
#include "../core/models/account.h"
|
||||
#include "../core/models/folder.h"
|
||||
#include "../core/mailitem.h"
|
||||
|
||||
class PopSynchronizer : public Synchronizer {
|
||||
public:
|
||||
explicit PopSynchronizer(QObject *parent = nullptr);
|
||||
|
||||
// Implement the core synchronization methods
|
||||
bool initialize(const Account &account) override;
|
||||
bool syncFolder(const Folder &folder) override;
|
||||
QVector<MailItem> fetchMailItems(const QString &folderId, qint64 sinceUid = 0) override;
|
||||
bool appendMailItem(const QString &folderId, const MailItem &item) override;
|
||||
bool updateMailItemFlags(const QString &folderId, const QString &itemUid, bool read, bool flagged) override;
|
||||
bool deleteMailItem(const QString &folderId, const QString &itemUid) override;
|
||||
|
||||
private:
|
||||
// Internal state related to POP synchronization (e.g., connection status)
|
||||
bool m_isConnected = false;
|
||||
};
|
||||
|
||||
#endif // POPSYNCHRONIZER_H
|
||||
@@ -1,21 +0,0 @@
|
||||
// poprequest.cpp
|
||||
#include "poprequest.h"
|
||||
#include "request.h"
|
||||
#include <QUrl>
|
||||
#include <QDebug>
|
||||
|
||||
PopRequest::PopRequest(Request* req) : Concreterequests() {}
|
||||
|
||||
Request* PopRequest::createRequest(const QString& type, const QString& target) {
|
||||
qDebug() << "PopRequest is handling request for target: " << target;
|
||||
|
||||
// Construct a request object for POP3 operations.
|
||||
Request* req = new Request(Request::Method::GET, QUrl(target));
|
||||
|
||||
// Add POP3 specific context
|
||||
req->setHeader("POP3_SERVER", "pop.example.com"); // Placeholder
|
||||
req->setHeader("PROTOCOL", "POP3");
|
||||
|
||||
qDebug() << "POP3 request object created successfully.";
|
||||
return req;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
// poprequest.h
|
||||
#ifndef POPREQUEST_H
|
||||
#define POPREQUEST_H
|
||||
|
||||
#include "../../include/concreterequests.h"
|
||||
#include "../../include/request.h"
|
||||
|
||||
class PopRequest : public Concreterequests {
|
||||
public:
|
||||
PopRequest(Request* req);
|
||||
Request* createRequest(const QString& type, const QString& target) override;
|
||||
};
|
||||
|
||||
#endif // POPREQUEST_H
|
||||
@@ -1,74 +0,0 @@
|
||||
// src/services/popsynchronizer.cpp
|
||||
#include "popsynchronizer.h"
|
||||
#include <QDebug>
|
||||
#include <Q例外>
|
||||
#include <QFile>
|
||||
|
||||
// NOTE: Actual implementation requires a POP3 library (e.g., libpop3 or Qt's built-in network classes).
|
||||
// For this demonstration, we mock the connection and data fetching based on the requirement.
|
||||
|
||||
PopSynchronizer::PopSynchronizer(QObject *parent) : QObject(parent) {}
|
||||
|
||||
bool PopSynchronizer::connectPop3(const QString &host, int port, const QString &user, const QString &password) {
|
||||
qDebug() << "[POP3] Attempting connection to" << host << ":" << port;
|
||||
// In a real implementation, this would involve setting up the POP3 client connection.
|
||||
if (host.isEmpty() || port == 0) {
|
||||
qWarning() << "[POP3 Error] Host or Port is invalid.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mock successful connection for demonstration purposes.
|
||||
qDebug() << "[POP3 Success] Connected to server " << host;
|
||||
return true;
|
||||
}
|
||||
|
||||
QVector<MailItem> PopSynchronizer::fetchFromPop3(const QString &folderId, int offset) {
|
||||
if (!connectPop3("pop3.example.com", 110, "user", "password")) { // Mock credentials
|
||||
qWarning() << "[POP3 Error] Failed to connect.";
|
||||
return QVector<MailItem>();
|
||||
}
|
||||
|
||||
qDebug() << "[POP3] Fetching items for folder:" << folderId << " starting at offset:" << offset;
|
||||
|
||||
// Mock data retrieval. In a real scenario, this reads from the POP3 stream.
|
||||
QVector<MailItem> mails;
|
||||
if (folderId == "inbox") {
|
||||
mails.append(MailItem{ "mail_id_123", "Subject 1", "Body 1", true });
|
||||
mails.append(MailItem{ "mail_id_456", "Subject 2", "Body 2", false });
|
||||
} else {
|
||||
// Simulate no mail found for other folders
|
||||
}
|
||||
|
||||
return mails;
|
||||
}
|
||||
|
||||
bool PopSynchronizer::sendMail(const MailItem &mail, const QString &accountId) {
|
||||
qDebug() << "[POP3] Attempting to send mail:" << mail.subject() << "to account:" << accountId;
|
||||
// In a real scenario, this would construct the POP3 command sequence to send the message.
|
||||
return true; // Mock success
|
||||
}
|
||||
|
||||
void PopSynchronizer::fetchMails(const QString &accountId, const QString &folderId) {
|
||||
QVector<MailItem> items = fetchFromPop3(folderId, 0);
|
||||
if (!items.isEmpty()) {
|
||||
qDebug() << "[POP3] Successfully fetched" << items.size() << " mail items.";
|
||||
// The caller (MailService) will handle emitting the result.
|
||||
} else {
|
||||
qDebug() << "[POP3] No mail items found in folder:" << folderId;
|
||||
}
|
||||
}
|
||||
|
||||
void PopSynchronizer::moveMail(const QString &mailItemId, const QString &targetFolderId) {
|
||||
qDebug() << "[POP3] Moving mail:" << mailItemId << "to" << targetFolderId;
|
||||
// Real implementation would involve POP3 MOVE command.
|
||||
}
|
||||
|
||||
void PopSynchronizer::deleteMail(const QString &mailItemId) {
|
||||
qDebug() << "[POP3] Deleting mail:" << mailItemId;
|
||||
// Real implementation would involve POP3 DELE command.
|
||||
}
|
||||
|
||||
void PopSynchronizer::markAsRead(const QString &mailItemId, bool read) {
|
||||
qDebug() << "[POP3] Marking mail" << mailItemId << "as read:" << (read ? "True" : "False");
|
||||
// Real implementation would involve POP3 MARK_READ command.
|
||||
}
|
||||
@@ -1,35 +1,30 @@
|
||||
// src/services/popsynchronizer.h
|
||||
#ifndef POP_SYNCHRONIZER_H
|
||||
#define POP_SYNCHRONIZER_H
|
||||
#ifndef POP3SYNCHRONIZER_H
|
||||
#define POP3SYNCHRONIZER_H
|
||||
|
||||
#include "synchronizerprovider.h"
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QObject>
|
||||
// Asegúrate de incluir las definiciones necesarias de MailItem, etc. desde el proyecto.
|
||||
|
||||
class PopSynchronizer : public SynchronizerProvider
|
||||
{
|
||||
class PopSynchronizer : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PopSynchronizer(QObject *parent = nullptr);
|
||||
~PopSynchronizer() override = default;
|
||||
explicit PopSynchronizer(QObject *parent = nullptr);
|
||||
|
||||
bool isPop3Supported() const { return true; } // Indicate that this implementation supports POP3
|
||||
|
||||
// Implement the required methods from SynchronizerProvider
|
||||
QVector<MailItem> fetchMailItems(const QString &folderId, int offset) override;
|
||||
bool sendMail(const MailItem &mail, const QString &accountId) override;
|
||||
void fetchMails(const QString &accountId, const QString &folderId) override;
|
||||
void moveMail(const QString &mailItemId, const QString &targetFolderId) override;
|
||||
void deleteMail(const QString &mailItemId) override;
|
||||
void markAsRead(const QString &mailItemId, bool read) override;
|
||||
bool connectToPop3(const QString& host, const QString& user, const QString& password);
|
||||
QVector<MailItem> fetchMailItems(const QString &folderId, int offset);
|
||||
bool sendMail(const MailItem &mail, const QString &accountId);
|
||||
void fetchMails(const QString &accountId, const QString &folderId);
|
||||
void moveMail(const QString &mailItemId, const QString &targetFolderId);
|
||||
void deleteMail(const QString &mailItemId);
|
||||
void markAsRead(const QString &mailItemId, bool read);
|
||||
|
||||
private:
|
||||
// Private methods for actual POP3 logic
|
||||
bool connectPop3(const QString &host, int port, const QString &user, const QString &password);
|
||||
QVector<MailItem> fetchFromPop3(const QString &folderId, int offset);
|
||||
bool sendViaPop3(const MailItem &mail, const QString &accountId);
|
||||
void moveViaPop3(const QString &mailItemId, const QString &targetFolderId);
|
||||
void deleteViaPop3(const QString &mailItemId);
|
||||
void markReadViaPop3(const QString &mailItemId, bool read);
|
||||
bool m_isConnected = false;
|
||||
|
||||
signals:
|
||||
void connectionStatusChanged(bool success);
|
||||
|
||||
public slots:
|
||||
void processMailSync(); // Slot para iniciar la lógica de sincronización en segundo plano.
|
||||
};
|
||||
|
||||
#endif // POP_SYNCHRONIZER_H
|
||||
#endif // POP3SYNCHRONIZER_H
|
||||
@@ -1,19 +0,0 @@
|
||||
// smtprequest.cpp
|
||||
#include "smtprequest.h"
|
||||
#include "request.h"
|
||||
#include <QDebug>
|
||||
|
||||
SmtpRequest::SmtpRequest(Request* req) : Concreterequests(req) {}
|
||||
|
||||
Request* SmtpRequest::createRequest(const QString& type, const QString& target) {
|
||||
qDebug() << "SmtpRequest is handling request for target:" << target;
|
||||
|
||||
// In a real scenario, this would construct an SMTP-specific Request object.
|
||||
Request* req = new Request(Request::POST, target, QByteArray()); // Typically POST for sending mail
|
||||
|
||||
// Add specific context or headers if necessary for SMTP connection setup (to be implemented in Phase 2)
|
||||
req->headers["SMTP_SERVER"] = "smtp.example.com"; // Placeholder
|
||||
|
||||
qDebug() << "SMTP request object created successfully.";
|
||||
return req;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// /mnt/c/Users/javie/wino-mail-dtkqt/src/synchronizerprovider.cpp
|
||||
#include "synchronizerprovider.h"
|
||||
#include <QDebug>
|
||||
|
||||
SynchronizerProvider::SynchronizerProvider(QObject *parent) : QObject(parent) {}
|
||||
|
||||
void SynchronizerProvider::requestSync()
|
||||
{
|
||||
qDebug() << "SynchronizerProvider: Initiating data synchronization request...";
|
||||
|
||||
// Simulate the time taken for a network operation
|
||||
// In a real app, this is where you'd handle threading/asynchronous calls.
|
||||
|
||||
// Simulated Data Fetching (This should be replaced by actual IMAP/SMTP calls)
|
||||
QList<QString> folders = fetchFoldersFromBackend();
|
||||
QList<EmailItem> emails = QList<EmailItem>();
|
||||
|
||||
if (!folders.isEmpty()) {
|
||||
// Simulate fetching emails for the first folder if available, or all of them
|
||||
qDebug() << "Synchronizing data for" << folders.count() << "folders.";
|
||||
for (const QString& folder : folders) {
|
||||
// Simulate fetching emails from each folder
|
||||
QList<EmailItem> folderEmails = fetchEmailsFromBackend(folder);
|
||||
emails.append(folderEmails);
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Data synchronization complete. Total emails fetched:" << emails.count();
|
||||
|
||||
// Emit the result signal
|
||||
emit dataSynchronized(folders, emails);
|
||||
}
|
||||
|
||||
QList<QString> SynchronizerProvider::fetchFoldersFromBackend() const
|
||||
{
|
||||
// Simulated API call result
|
||||
return {"INBOX", "Sent", "Drafts", "Archive"};
|
||||
}
|
||||
|
||||
QList<EmailItem> SynchronizerProvider::fetchEmailsFromBackend(const QString& folder) const
|
||||
{
|
||||
// Simulated API call result based on folder logic
|
||||
if (folder == "INBOX") {
|
||||
return {
|
||||
{1, "Test Email 1", "test@example.com"},
|
||||
{2, "Important Update", "other@example.com"}
|
||||
};
|
||||
} else if (folder == "Sent") {
|
||||
return {
|
||||
{3, "Sent Mail A", "me@example.com"}
|
||||
};
|
||||
}
|
||||
return QList<EmailItem>();
|
||||
}
|
||||
@@ -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() ? "Sí" : "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"
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -77,4 +77,5 @@ private:
|
||||
|
||||
QToolBar *m_toolBar;
|
||||
int m_currentFolderId;
|
||||
int m_currentMailId;
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user