Baseline for wino-mail-dtkqt UI migration
This commit is contained in:
Binary file not shown.
+25
-15
@@ -9,33 +9,43 @@ Authenticator::Authenticator(QObject *parent)
|
|||||||
|
|
||||||
void Authenticator::exchangeAuthorizationCode(const QString &code, const QString &redirectUri)
|
void Authenticator::exchangeAuthorizationCode(const QString &code, const QString &redirectUri)
|
||||||
{
|
{
|
||||||
Q_UNUSED(code);
|
QUrl url(m_tokenEndpoint);
|
||||||
Q_UNUSED(redirectUri);
|
QNetworkRequest request = createTokenRequest(url);
|
||||||
qDebug() << "[Authenticator] exchangeAuthorizationCode called (base implementation)";
|
|
||||||
|
QByteArray postData;
|
||||||
|
postData.append("grant_type=authorization_code");
|
||||||
|
postData.append("&code=" + code.toUtf8());
|
||||||
|
postData.append("&redirect_uri=" + redirectUri.toUtf8());
|
||||||
|
postData.append("&client_id=" + QString(m_clientId).toUtf8());
|
||||||
|
postData.append("&client_secret=" + QString(m_clientSecret).toUtf8());
|
||||||
|
|
||||||
|
QNetworkReply *reply = m_networkManager->post(request, postData);
|
||||||
|
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||||
|
handleTokenResponse(reply->readAll(), m_email, providerName());
|
||||||
|
reply->deleteLater();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Authenticator::handleTokenResponse(const QByteArray &data, const QString &email, const QString &providerType)
|
void Authenticator::handleTokenResponse(const QByteArray &data, const QString &email, const QString &providerType)
|
||||||
{
|
{
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data);
|
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||||
if (doc.isNull() || !doc.isObject()) {
|
if (!doc.isObject()) {
|
||||||
emit authenticationFailed("Invalid token response");
|
emit authenticationFailed("Invalid response from server");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject obj = doc.object();
|
QJsonObject obj = doc.object();
|
||||||
QString accessToken = obj["access_token"].toString();
|
if (obj.contains("error")) {
|
||||||
QString refreshToken = obj["refresh_token"].toString();
|
emit authenticationFailed(obj["error"].toString() + ": " + obj["error_description"].toString());
|
||||||
int expiresIn = obj["expires_in"].toInt();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Account account;
|
Account account;
|
||||||
account.setEmail(email);
|
account.setEmail(email);
|
||||||
account.setAccessToken(accessToken);
|
account.setProvider(providerType);
|
||||||
account.setRefreshToken(refreshToken);
|
account.setAccessToken(obj["access_token"].toString());
|
||||||
account.setTokenExpires(QDateTime::currentDateTimeUtc().addSecs(expiresIn));
|
account.setRefreshToken(obj["refresh_token"].toString());
|
||||||
|
account.setTokenExpires(QDateTime::currentDateTimeUtc().addSecs(obj["expires_in"].toInt()));
|
||||||
if (providerType == "gmail") account.setType(AccountType::Gmail);
|
|
||||||
else if (providerType == "outlook") account.setType(AccountType::Outlook);
|
|
||||||
else account.setType(AccountType::IMAP);
|
|
||||||
|
|
||||||
emit authenticationCompleted(account);
|
emit authenticationCompleted(account);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ GmailAuthenticator::GmailAuthenticator(QObject *parent)
|
|||||||
connect(m_callbackServer, &OAuthCallbackServer::codeReceived,
|
connect(m_callbackServer, &OAuthCallbackServer::codeReceived,
|
||||||
this, &GmailAuthenticator::onAuthCodeReceived);
|
this, &GmailAuthenticator::onAuthCodeReceived);
|
||||||
connect(m_callbackServer, &OAuthCallbackServer::errorOccurred,
|
connect(m_callbackServer, &OAuthCallbackServer::errorOccurred,
|
||||||
this, [this](const QString &error) {
|
[this](const QString &error) {
|
||||||
emit authenticationFailed("OAuth callback error: " + error);
|
emit authenticationFailed("OAuth callback error: " + error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -66,19 +66,8 @@ void GmailAuthenticator::onAuthCodeReceived(const QString &code, const QString &
|
|||||||
|
|
||||||
m_authCode = code;
|
m_authCode = code;
|
||||||
|
|
||||||
// Exchange the authorization code for tokens
|
// Exchange the authorization code for tokens using base class implementation
|
||||||
QUrlQuery params;
|
exchangeAuthorizationCode(code, m_redirectUri);
|
||||||
params.addQueryItem("code", code);
|
|
||||||
params.addQueryItem("client_id", m_clientId);
|
|
||||||
params.addQueryItem("client_secret", m_clientSecret);
|
|
||||||
params.addQueryItem("redirect_uri", m_redirectUri);
|
|
||||||
params.addQueryItem("grant_type", "authorization_code");
|
|
||||||
|
|
||||||
QNetworkRequest request = createTokenRequest(QUrl(m_tokenEndpoint));
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, params.toString(QUrl::FullyEncoded).toUtf8());
|
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
|
||||||
onTokenReply(reply);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GmailAuthenticator::refreshToken(const Account &account)
|
void GmailAuthenticator::refreshToken(const Account &account)
|
||||||
@@ -94,23 +83,9 @@ void GmailAuthenticator::refreshToken(const Account &account)
|
|||||||
QNetworkRequest request = createTokenRequest(QUrl(m_tokenEndpoint));
|
QNetworkRequest request = createTokenRequest(QUrl(m_tokenEndpoint));
|
||||||
QNetworkReply *reply = m_networkManager->post(request, params.toString(QUrl::FullyEncoded).toUtf8());
|
QNetworkReply *reply = m_networkManager->post(request, params.toString(QUrl::FullyEncoded).toUtf8());
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||||
onTokenReply(reply);
|
handleTokenResponse(reply->readAll(), m_email, "gmail");
|
||||||
|
reply->deleteLater();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GmailAuthenticator::onTokenReply(QNetworkReply *reply)
|
#include "gmailauthenticator.moc"
|
||||||
{
|
|
||||||
if (reply->error() == QNetworkReply::NoError) {
|
|
||||||
QByteArray data = reply->readAll();
|
|
||||||
handleTokenResponse(data, m_email, "gmail");
|
|
||||||
} else {
|
|
||||||
QByteArray responseData = reply->readAll();
|
|
||||||
qWarning() << "[GmailAuthenticator] Token request failed:"
|
|
||||||
<< reply->errorString()
|
|
||||||
<< "Response:" << QString::fromUtf8(responseData);
|
|
||||||
emit authenticationFailed("Gmail token request failed: " + reply->errorString());
|
|
||||||
}
|
|
||||||
reply->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "gmailauthenticator.moc"
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ OutlookAuthenticator::OutlookAuthenticator(QObject *parent)
|
|||||||
connect(m_callbackServer, &OAuthCallbackServer::codeReceived,
|
connect(m_callbackServer, &OAuthCallbackServer::codeReceived,
|
||||||
this, &OutlookAuthenticator::onAuthCodeReceived);
|
this, &OutlookAuthenticator::onAuthCodeReceived);
|
||||||
connect(m_callbackServer, &OAuthCallbackServer::errorOccurred,
|
connect(m_callbackServer, &OAuthCallbackServer::errorOccurred,
|
||||||
this, [this](const QString &error) {
|
[this](const QString &error) {
|
||||||
emit authenticationFailed("OAuth callback error: " + error);
|
emit authenticationFailed("OAuth callback error: " + error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -58,18 +58,7 @@ void OutlookAuthenticator::onAuthCodeReceived(const QString &code, const QString
|
|||||||
|
|
||||||
m_callbackServer->stop();
|
m_callbackServer->stop();
|
||||||
|
|
||||||
QUrlQuery params;
|
exchangeAuthorizationCode(code, m_redirectUri);
|
||||||
params.addQueryItem("code", code);
|
|
||||||
params.addQueryItem("client_id", m_clientId);
|
|
||||||
params.addQueryItem("client_secret", m_clientSecret);
|
|
||||||
params.addQueryItem("redirect_uri", m_redirectUri);
|
|
||||||
params.addQueryItem("grant_type", "authorization_code");
|
|
||||||
|
|
||||||
QNetworkRequest request = createTokenRequest(QUrl(m_tokenEndpoint));
|
|
||||||
QNetworkReply *reply = m_networkManager->post(request, params.toString(QUrl::FullyEncoded).toUtf8());
|
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
|
||||||
onTokenReply(reply);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutlookAuthenticator::refreshToken(const Account &account)
|
void OutlookAuthenticator::refreshToken(const Account &account)
|
||||||
@@ -86,23 +75,9 @@ void OutlookAuthenticator::refreshToken(const Account &account)
|
|||||||
QNetworkRequest request = createTokenRequest(QUrl(m_tokenEndpoint));
|
QNetworkRequest request = createTokenRequest(QUrl(m_tokenEndpoint));
|
||||||
QNetworkReply *reply = m_networkManager->post(request, params.toString(QUrl::FullyEncoded).toUtf8());
|
QNetworkReply *reply = m_networkManager->post(request, params.toString(QUrl::FullyEncoded).toUtf8());
|
||||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||||
onTokenReply(reply);
|
handleTokenResponse(reply->readAll(), m_email, "outlook");
|
||||||
|
reply->deleteLater();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void OutlookAuthenticator::onTokenReply(QNetworkReply *reply)
|
#include "outlookauthenticator.moc"
|
||||||
{
|
|
||||||
if (reply->error() == QNetworkReply::NoError) {
|
|
||||||
QByteArray data = reply->readAll();
|
|
||||||
handleTokenResponse(data, m_email, "outlook");
|
|
||||||
} else {
|
|
||||||
QByteArray responseData = reply->readAll();
|
|
||||||
qWarning() << "[OutlookAuthenticator] Token request failed:"
|
|
||||||
<< reply->errorString()
|
|
||||||
<< "Response:" << QString::fromUtf8(responseData);
|
|
||||||
emit authenticationFailed("Outlook token request failed: " + reply->errorString());
|
|
||||||
}
|
|
||||||
reply->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "outlookauthenticator.moc"
|
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ void MailListView::setupUI() {
|
|||||||
m_tableView->setModel(m_proxyModel);
|
m_tableView->setModel(m_proxyModel);
|
||||||
|
|
||||||
connect(m_tableView, &QTableView::clicked, this, &MailListView::onRowSelected);
|
connect(m_tableView, &QTableView::clicked, this, &MailListView::onRowSelected);
|
||||||
|
connect(m_tableView, &QTableView::doubleClicked, this, [this](const QModelIndex &index) {
|
||||||
|
if (!index.isValid()) return;
|
||||||
|
QModelIndex sourceIndex = m_proxyModel->mapToSource(index);
|
||||||
|
int mailId = sourceIndex.data(EmailListModel::IdRole).toInt();
|
||||||
|
emit emailOpenRequested(mailId);
|
||||||
|
});
|
||||||
|
|
||||||
layout->addWidget(m_tableView);
|
layout->addWidget(m_tableView);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void emailSelected(int mailId);
|
void emailSelected(int mailId);
|
||||||
|
void emailOpenRequested(int mailId);
|
||||||
void composeRequested();
|
void composeRequested();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|||||||
@@ -164,12 +164,21 @@ void MainMainWindow::setupMailPage() {
|
|||||||
m_mailListView = new MailListView();
|
m_mailListView = new MailListView();
|
||||||
connect(m_mailListView, &MailListView::emailSelected, this, &MainMainWindow::onEmailSelected);
|
connect(m_mailListView, &MailListView::emailSelected, this, &MainMainWindow::onEmailSelected);
|
||||||
connect(m_mailListView, &MailListView::composeRequested, this, &MainMainWindow::onComposeRequested);
|
connect(m_mailListView, &MailListView::composeRequested, this, &MainMainWindow::onComposeRequested);
|
||||||
|
connect(m_mailListView, &MailListView::emailOpenRequested, this, [this](int mailId) {
|
||||||
|
openMailInIndependentWindow(mailId);
|
||||||
|
});
|
||||||
m_folderSplitter->addWidget(m_mailListView);
|
m_folderSplitter->addWidget(m_mailListView);
|
||||||
|
|
||||||
// Reader
|
// Reader
|
||||||
m_emailViewer = new ReaderView();
|
m_emailViewer = new ReaderView();
|
||||||
m_emailViewer->setMinimumWidth(350);
|
m_emailViewer->setMinimumWidth(350);
|
||||||
connect(m_emailViewer, &ReaderView::replyRequested, this, &MainMainWindow::onReaderReplyRequested);
|
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());
|
||||||
|
}
|
||||||
|
});
|
||||||
m_folderSplitter->addWidget(m_emailViewer);
|
m_folderSplitter->addWidget(m_emailViewer);
|
||||||
|
|
||||||
// Default sizes: folder 240, list 380, reader flex
|
// Default sizes: folder 240, list 380, reader flex
|
||||||
@@ -248,6 +257,24 @@ void MainMainWindow::onNewMessage() {
|
|||||||
switchToPage(PageCompose);
|
switchToPage(PageCompose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainMainWindow::openMailInIndependentWindow(int mailId) {
|
||||||
|
std::optional<MailItem> item = MailItemDao::findById(mailId);
|
||||||
|
if (!item.has_value()) return;
|
||||||
|
|
||||||
|
QMainWindow *detachedWin = new QMainWindow();
|
||||||
|
detachedWin->setWindowTitle(QString("Mail - %1").arg(item->subject()));
|
||||||
|
|
||||||
|
ReaderView *detachedReader = new ReaderView();
|
||||||
|
detachedReader->setMailItem(&item.value());
|
||||||
|
|
||||||
|
detachedWin->setCentralWidget(detachedReader);
|
||||||
|
detachedWin->resize(800, 600);
|
||||||
|
detachedWin->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
|
detachedWin->show();
|
||||||
|
|
||||||
|
statusBar()->showMessage("Opened mail in independent window", 3000);
|
||||||
|
}
|
||||||
|
|
||||||
void MainMainWindow::createToolBar() {
|
void MainMainWindow::createToolBar() {
|
||||||
m_toolBar = addToolBar("Main Toolbar");
|
m_toolBar = addToolBar("Main Toolbar");
|
||||||
m_toolBar->setMovable(false);
|
m_toolBar->setMovable(false);
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ private slots:
|
|||||||
void onComposeRequested();
|
void onComposeRequested();
|
||||||
void onReaderReplyRequested(const MailItem *item);
|
void onReaderReplyRequested(const MailItem *item);
|
||||||
void onNewMessage();
|
void onNewMessage();
|
||||||
|
void openMailInIndependentWindow(int mailId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupUI();
|
void setupUI();
|
||||||
|
|||||||
@@ -40,9 +40,13 @@ void ReaderView::setupUI() {
|
|||||||
m_forwardButton = new QPushButton("Forward");
|
m_forwardButton = new QPushButton("Forward");
|
||||||
m_deleteButton = new QPushButton("Delete");
|
m_deleteButton = new QPushButton("Delete");
|
||||||
m_deleteButton->setStyleSheet("color: red;");
|
m_deleteButton->setStyleSheet("color: red;");
|
||||||
|
|
||||||
|
QPushButton *m_detachButton = new QPushButton("独立 (Independent)");
|
||||||
|
m_detachButton->setToolTip("Open in separate window");
|
||||||
|
|
||||||
actionsLayout->addWidget(m_replyButton);
|
actionsLayout->addWidget(m_replyButton);
|
||||||
actionsLayout->addWidget(m_forwardButton);
|
actionsLayout->addWidget(m_forwardButton);
|
||||||
|
actionsLayout->addWidget(m_detachButton);
|
||||||
actionsLayout->addStretch();
|
actionsLayout->addStretch();
|
||||||
actionsLayout->addWidget(m_deleteButton);
|
actionsLayout->addWidget(m_deleteButton);
|
||||||
|
|
||||||
@@ -59,6 +63,8 @@ void ReaderView::setupUI() {
|
|||||||
connect(m_replyButton, &QPushButton::clicked, [this]() {
|
connect(m_replyButton, &QPushButton::clicked, [this]() {
|
||||||
if (m_bodyViewer->toPlainText().isEmpty()) return;
|
if (m_bodyViewer->toPlainText().isEmpty()) return;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(m_detachButton, &QPushButton::clicked, this, &ReaderView::detachRequested);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReaderView::setMailItem(const MailItem* item) {
|
void ReaderView::setMailItem(const MailItem* item) {
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ signals:
|
|||||||
void replyRequested(const MailItem* item);
|
void replyRequested(const MailItem* item);
|
||||||
void forwardRequested(const MailItem* item);
|
void forwardRequested(const MailItem* item);
|
||||||
void deleteRequested(const MailItem* item);
|
void deleteRequested(const MailItem* item);
|
||||||
|
void detachRequested();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupUI();
|
void setupUI();
|
||||||
|
|||||||
Reference in New Issue
Block a user