Fix build: synchronize Request API, fix GmailSynchronizer, and migrate UI to Qt6 Widgets

This commit is contained in:
2026-06-17 22:44:27 +02:00
parent dcb7c52269
commit 0e9f620fe0
348 changed files with 118736 additions and 1207 deletions
-19
View File
@@ -1,19 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Item {
id: calendarPage
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "#fafafa"
Text {
text: qsTr("Calendar Page - Placeholder")
anchors.centerIn: parent
font.pointSize: 16
color: "#666"
}
}
}
-147
View File
@@ -1,147 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtWebEngine 1.15
import QtQml 2.15
Item {
id: composePage
anchors.fill: parent
// Expose a bridge to C++ for sending email and getting Quill content
property var emailBridge: emailComposerBridge
// Back button
Rectangle {
anchors {
top: parent.top
left: parent.left
margins: 10
}
width: 40
height: 40
color: "#e0e0e0"
radius: 5
MouseArea {
anchors.fill: parent
onClicked: {
StackView.view.pop()
}
}
Text {
text: "←"
anchors.centerIn: parent
font.pointSize: 20
color: "#333"
}
}
// Form for composing email
Rectangle {
anchors {
top: backButton.bottom
bottom: parent.bottom
left: parent.left
right: parent.right
margins: 10
}
color: "#fafafa"
ColumnLayout {
anchors.fill: parent
spacing: 10
// To field
Text {
text: qsTr("To:")
font.pointSize: 14
Layout.alignment: Qt.AlignLeft
}
TextField {
id: toField
placeholderText: qsTr("Recipient")
Layout.fillWidth: true
}
// Subject field
Text {
text: qsTr("Subject:")
font.pointSize: 14
Layout.alignment: Qt.AlignLeft
}
TextField {
id: subjectField
placeholderText: qsTr("Subject")
Layout.fillWidth: true
}
// Body - WebEngineView loading editor.html with Quill
Text {
text: qsTr("Body:")
font.pointSize: 14
Layout.alignment: Qt.AlignLeft
}
WebEngineView {
id: bodyWebView
Layout.fillWidth: true
Layout.fillHeight: true
url: "qrc:/resources/web/editor.html"
// Settings to enable webchannel
settings.javascriptEnabled: true
settings.localContentCanAccessRemoteUrls: true
settings.localContentCanAccessFileUrls: true
}
// Attachments area (simple list placeholder)
RowLayout {
id: attachmentsRow
Layout.fillWidth: true
spacing: 5
// Will be populated dynamically via C++ model or JS array
// For now, placeholder
Text {
text: qsTr("Attachments: ")
font.pointSize: 12
}
Text {
id: attachmentsText
text: qsTr("None")
font.pointSize: 12
color: "#666"
}
Button {
text: qsTr("Attach")
onClicked: {
// Call C++ to open file dialog and get selected files
emailBridge.openAttachmentDialog()
}
}
}
// Send button
Rectangle {
id: sendButton
Layout.alignment: Qt.AlignRight
width: 80
height: 30
color: "#1976D2"
radius: 4
MouseArea {
anchors.fill: parent
onClicked: {
// Trigger sending via bridge
emailBridge.sendComposedEmail(
toField.text,
subjectField.text
)
}
}
Text {
text: qsTr("Send")
color: "white"
anchors.centerIn: parent
font.pointSize: 12
}
}
}
}
}
-19
View File
@@ -1,19 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Item {
id: contactsPage
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "#fafafa"
Text {
text: qsTr("Contacts Page - Placeholder")
anchors.centerIn: parent
font.pointSize: 16
color: "#666"
}
}
}
-186
View File
@@ -1,186 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Item {
id: mailListPage
anchors.fill: parent
// Models
FolderListModel {
id: folderModel
}
EmailListModel {
id: emailModel
}
// Signals
signal emailSelected(int emailId)
signal composeRequested
// Header
Rectangle {
id: header
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 50
color: "#1976D2"
// Title
Text {
text: qsTr("Wino Mail")
color: "white"
font.pointSize: 18
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 16
}
// Compose button
Rectangle {
id: composeButton
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: 10
width: 40
height: 40
color: "#e0e0e0"
radius: 5
MouseArea {
anchors.fill: parent
onClicked: {
mailListPage.composeRequested()
}
}
Text {
text: "✎"
anchors.centerIn: parent
font.pointSize: 20
color: "#333"
}
}
}
// Main content: SplitView for folder list and email list
SplitView {
anchors {
top: header.bottom
bottom: parent.bottom
left: parent.left
right: parent.right
}
// Left pane: Folder list
Rectangle {
width: 200
color: "#fafafa"
ListView {
id: folderListView
anchors.fill: parent
clip: true
model: folderModel
delegate: Item {
height: 40
Layout.fillWidth: true
Rectangle {
anchors.fill: parent
color: ListView.isCurrentItem ? "#e3f2fd" : "transparent"
Text {
text: folderName
anchors.left: parent.left
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
font.pointSize: 14
color: ListView.isCurrentItem ? "#1976d2" : "#666"
}
}
MouseArea {
anchors.fill: parent
onClicked: {
folderListView.currentIndex = index
// Load emails for selected folder
// For now, we'll map folder names to IDs (hardcoded for demo)
var folderId = 0; // Inbox
switch (folderName) {
case "Inbox": folderId = 0; break;
case "Sent": folderId = 1; break;
case "Drafts": folderId = 2; break;
case "Trash": folderId = 3; break;
case "Spam": folderId = 4; break;
default: folderId = 0;
}
emailModel.setFolderId(folderId);
}
}
}
}
}
// Right pane: Email list (full height)
Rectangle {
color: "#fafafa"
ListView {
id: emailListView
anchors.fill: parent
clip: true
model: emailModel
delegate: Item {
height: 60
Layout.fillWidth: true
Rectangle {
anchors.fill: parent
color: ListView.isCurrentItem ? "#e3f2fd" : "transparent"
RowLayout {
anchors.fill: parent
anchors.margins: 8
// Sender avatar/initial
Rectangle {
width: 40
height: 40
color: "#cccccc"
Text {
text: senderInitial
anchors.centerIn: parent
font.pointSize: 16
color: "#666"
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 4
Text {
text: senderName
font.pointSize: 14
color: "#333"
elide: Text.ElideRight
Layout.fillWidth: true
}
Text {
text: subject
font.pointSize: 13
color: "#666"
elide: Text.ElideRight
Layout.fillWidth: true
}
Text {
text: time
font.pointSize: 12
color: "#999"
}
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
emailListView.currentIndex = index
// Emit signal with email id
emailSelected(model.id)
}
}
}
}
}
}
}
-67
View File
@@ -1,67 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtWebEngine 1.15
Item {
id: readerPage
anchors.fill: parent
// Property to hold the email ID to display
property int emailId: -1
// Called when the page is activated
Component.onCompleted: {
if (emailId !== -1) {
loadEmail(emailId)
}
}
// Function to load email by ID
function loadEmail(id) {
emailId = id
// Fetch the HTML content from the EmailManager
webView.html = emailManager.getEmailHtmlById(id)
}
// Back button
Rectangle {
anchors {
top: parent.top
left: parent.left
margins: 10
}
width: 40
height: 40
color: "#e0e0e0"
radius: 5
MouseArea {
anchors.fill: parent
onClicked: {
StackView.view.pop()
}
}
Text {
text: "←"
anchors.centerIn: parent
font.pointSize: 20
color: "#333"
}
}
// Main content: WebEngineView to display email
WebEngineView {
id: webView
anchors {
top: backButton.bottom
bottom: parent.bottom
left: parent.left
right: parent.right
margins: 0
}
// Settings to enable local content loading
settings.javascriptEnabled: true
settings.localContentCanAccessRemoteUrls: true
settings.localContentCanAccessFileUrls: true
}
}
-191
View File
@@ -1,191 +0,0 @@
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Item {
id: settingsPage
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "#fafafa"
ColumnLayout {
anchors.fill: parent
anchors.margins: 20
spacing: 20
// Accounts section
GroupBox {
title: qsTr("Email Accounts")
Layout.fillWidth: true
Layout.preferredHeight: 200
ColumnLayout {
anchors.fill: parent
anchors.margins: 15
spacing: 10
// Accounts list placeholder
ListView {
id: accountsListView
Layout.fillWidth: true
Layout.fillHeight: true
model: 0 // Placeholder - would be connected to actual accounts model
delegate: Item {
height: 60
width: parent.width
Rectangle {
anchors.fill: parent
color: "#ffffff"
radius: 4
border.color: "#e0e0e0"
RowLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 10
Image {
source: "account-outline.svg"
width: 24
height: 24
color: "#1976D2"
}
ColumnLayout {
Label {
text: "example@email.com"
font.bold: true
color: "#333"
}
Label {
text: "Outlook • john.doe@example.com"
font.pointSize: 10
color: "#666"
}
}
Item {
Layout.fillWidth: true
}
IconButton {
icon: "edit"
iconSize: 20
color: "#666"
onClicked: {
// Would open edit account dialog
}
}
IconButton {
icon: "delete"
iconSize: 20
color: "#f44336"
onClicked: {
// Would delete account
}
}
}
}
}
}
// Add account button
RowLayout {
Layout.fillWidth: true
Button {
text: qsTr("Add Email Account")
icon: "plus"
Layout.fillWidth: true
height: 40
onClicked: {
accountSetupDialogLauncher.showDialog()
}
}
}
}
}
// General settings section
GroupBox {
title: qsTr("General Settings")
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 15
spacing: 15
Switch {
text: qsTr("Start application on login")
checked: true
}
Switch {
text: qsTr("Enable notifications")
checked: true
}
Switch {
text: qsTr("Minimize to tray on close")
checked: true
}
Label {
text: qsTr("Sync Interval:")
font.bold: true
}
RowLayout {
ComboBox {
width: 100
model: [15, 30, 60, 120]
textRole: "display"
currentIndex: 1 // 30 minutes
}
Label {
text: qsTr("minutes")
}
}
}
}
// Appearance section
GroupBox {
title: qsTr("Appearance")
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 15
spacing: 15
Label {
text: qsTr("Theme:")
font.bold: true
}
RowLayout {
RadioButton {
text: qsTr("Light")
checked: true
}
RadioButton {
text: qsTr("Dark")
}
RadioButton {
text: qsTr("System")
}
}
Switch {
text: qsTr("Use Deepin theme")
checked: true
}
}
}
}
}
}
-161
View File
@@ -1,161 +0,0 @@
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
ApplicationWindow {
id: shell
visible: true
width: 1024
height: 768
title: qsTr("Wino Mail Qt")
// Set the title from translator in Component.onCompleted
Component.onCompleted: {
title = translator.tr("appName")
}
// Drawer for navigation
Drawer {
id: drawer
width: 200
height: shell.height
Container {
anchors.fill: parent
Layout.alignment: Qt.AlignTop
ScrollView {
anchors.fill: parent
ColumnLayout {
spacing: 0
// App logo/name
Rectangle {
Layout.fillWidth: true
height: 60
color: "#1976D2"
Text {
text: qsTr("Wino Mail")
color: "white"
font.pointSize: 18
anchors.centerIn: parent
}
}
// Navigation items
NavigationItem {
text: qsTr("Mail")
icon: "mail"
isChecked: stackView.currentIndex === 0
onClicked: {
drawer.close()
stackView.currentIndex = 0
}
}
NavigationItem {
text: qsTr("Calendar")
icon: "calendar"
isChecked: stackView.currentIndex === 1
onClicked: {
drawer.close()
stackView.currentIndex = 1
}
}
NavigationItem {
text: qsTr("Contacts")
icon: "contacts"
isChecked: stackView.currentIndex === 2
onClicked: {
drawer.close()
stackView.currentIndex = 2
}
}
NavigationItem {
text: qsTr("Settings")
icon: "settings"
isChecked: stackView.currentIndex === 3
onClicked: {
drawer.close()
stackView.currentIndex = 3
}
}
}
}
}
}
// Define pages
MailListPage {
id: mailListPage
onEmailSelected: {
stackView.push(readerPage, { "emailId": emailId })
}
onComposeRequested: {
stackView.push(composePage)
}
}
ReaderPage {
id: readerPage
}
ComposePage {
id: composePage
}
// Placeholder for other pages
CalendarPage {
id: calendarPage
}
ContactsPage {
id: contactsPage
}
SettingsPage {
id: settingsPage
}
// Main content area with StackView for pages
StackView {
id: stackView
anchors.fill: parent
initialItem: mailListPage
}
// Hamburger button to open drawer
MenuButton {
icon: "menu"
anchors.left: parent.left
anchors.top: parent.top
anchors.margins: 10
onClicked: drawer.open()
}
}
// Helper components
component NavigationItem: Button {
Layout.fillWidth: true
height: 48
padding: 0
contentItem: RowLayout {
spacing: 16
anchors.fill: parent
anchors.margins: 24
Icon {
source: icon
width: 24
height: 24
color: isChecked ? "#1976D2" : "#666"
}
Text {
text: text
font.pointSize: 14
verticalAlignment: Text.AlignVCenter
color: isChecked ? "#1976D2" : "#666"
}
}
background: Rectangle {
color: isChecked ? "#E3F2FD" : "transparent"
radius: 0
}
}
component MenuButton: IconButton {
iconSource: icon
}
-7
View File
@@ -1,7 +0,0 @@
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
// We'll load the Shell component from Shell.qml
Shell {
}
-24
View File
@@ -1,24 +0,0 @@
import QtQuick 2.15
ListModel {
ListElement {
folderName: "Inbox"
unreadCount: 5
}
ListElement {
folderName: "Sent"
unreadCount: 0
}
ListElement {
folderName: "Drafts"
unreadCount: 0
}
ListElement {
folderName: "Trash"
unreadCount: 0
}
ListElement {
folderName: "Spam"
unreadCount: 0
}
}