diff --git a/internal/frontend/bridge-gui/bridge-gui/Resources.qrc b/internal/frontend/bridge-gui/bridge-gui/Resources.qrc
index d3651c83..e2c6df5a 100644
--- a/internal/frontend/bridge-gui/bridge-gui/Resources.qrc
+++ b/internal/frontend/bridge-gui/bridge-gui/Resources.qrc
@@ -106,7 +106,6 @@
qml/Resources/bug_report_flow.json
qml/SettingsItem.qml
qml/SettingsView.qml
- qml/SetupGuide.qml
qml/SetupWizard/ClientListItem.qml
qml/SetupWizard/LeftPane.qml
qml/SetupWizard/ClientConfigOutlookSelector.qml
@@ -117,11 +116,9 @@
qml/SetupWizard/Login.qml
qml/SetupWizard/Onboarding.qml
qml/SetupWizard/StepDescriptionBox.qml
- qml/SignIn.qml
qml/ConnectionModeSettings.qml
qml/SplashScreen.qml
qml/Status.qml
- qml/WelcomeGuide.qml
qml/WebViewWindow.qml
diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/AccountView.qml b/internal/frontend/bridge-gui/bridge-gui/qml/AccountView.qml
index ff196d43..f3a6b70a 100644
--- a/internal/frontend/bridge-gui/bridge-gui/qml/AccountView.qml
+++ b/internal/frontend/bridge-gui/bridge-gui/qml/AccountView.qml
@@ -29,7 +29,7 @@ Item {
property var user
signal showSetupGuide(var user, string address)
- signal showSignIn
+ signal showSignIn(var username)
Rectangle {
anchors.fill: parent
@@ -92,9 +92,9 @@ Item {
visible: root.user ? (root.user.state === EUserState.SignedOut) : false
onClicked: {
- if (!root.user)
- return;
- root.showSignIn();
+ if (user) {
+ root.showSignIn(user.primaryEmailOrUsername());
+ }
}
}
Button {
@@ -124,7 +124,7 @@ Item {
showSeparator: splitMode.visible
text: qsTr("Email clients")
type: SettingsItem.Button
- visible: _connected && (!root.user.splitMode) || (root.user.addresses.length === 1)
+ visible: _connected && ((!root.user.splitMode) || (root.user.addresses.length === 1))
onClicked: {
if (!root.user)
diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/ContentWrapper.qml b/internal/frontend/bridge-gui/bridge-gui/qml/ContentWrapper.qml
index 55e8ee51..ed24436e 100644
--- a/internal/frontend/bridge-gui/bridge-gui/qml/ContentWrapper.qml
+++ b/internal/frontend/bridge-gui/bridge-gui/qml/ContentWrapper.qml
@@ -25,7 +25,8 @@ Item {
signal closeWindow
signal quitBridge
signal showSetupGuide(var user, string address)
- signal showSetupWizard
+ signal showSignIn(var username)
+ signal showSetupWizard()
function selectUser(userID) {
const users = Backend.users;
@@ -50,10 +51,6 @@ Item {
function showSettings() {
rightContent.showGeneralSettings();
}
- function showSignIn(username) {
- signIn.username = username;
- rightContent.showSignIn();
- }
RowLayout {
anchors.fill: parent
@@ -234,8 +231,7 @@ Item {
if (user.state !== EUserState.SignedOut) {
rightContent.showAccount();
} else {
- signIn.username = user.primaryEmailOrUsername();
- rightContent.showSignIn();
+ showSignIn(user.primaryEmailOrUsername());
}
}
}
@@ -283,8 +279,7 @@ Item {
width: 36
onClicked: {
- signIn.username = "";
- root.showSetupWizard();
+ root.showSignIn("")
}
}
}
@@ -324,10 +319,6 @@ Item {
function showPortSettings() {
rightContent.currentIndex = 4;
}
- function showSignIn() {
- rightContent.currentIndex = 1;
- signIn.focus = true;
- }
anchors.fill: parent
@@ -346,42 +337,14 @@ Item {
onShowSetupGuide: function (user, address) {
root.showSetupGuide(user, address);
}
- onShowSignIn: {
- const user = this.user;
- signIn.username = user ? user.primaryEmailOrUsername() : "";
- rightContent.showSignIn();
+ onShowSignIn: function (username) {
+ root.showSignIn(username)
}
}
- GridLayout {
- // 1 Sign In
- columns: 2
-
- Button {
- id: backButton
- Layout.alignment: Qt.AlignTop
- Layout.leftMargin: 18
- Layout.topMargin: 10
- colorScheme: root.colorScheme
- horizontalPadding: 8
- icon.source: "/qml/icons/ic-arrow-left.svg"
- secondary: true
-
- onClicked: {
- signIn.abort();
- rightContent.showAccount();
- }
- }
- SignIn {
- id: signIn
- Layout.bottomMargin: 68
- Layout.fillHeight: true
- Layout.fillWidth: true
- Layout.leftMargin: 80 - backButton.width - 18
- Layout.preferredWidth: 320
- Layout.rightMargin: 80
- Layout.topMargin: 68
- colorScheme: root.colorScheme
- }
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ color: "#ff9900"
}
GeneralSettings {
// 2
diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml b/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml
index 7fb46a0e..309f6906 100644
--- a/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml
+++ b/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml
@@ -46,21 +46,38 @@ ApplicationWindow {
contentWrapper.showSettings();
}
function showSetup(user, address) {
- setupGuide.user = user;
- setupGuide.address = address;
- setupGuide.reset();
- contentLayout._showSetup = !!setupGuide.user;
+ contentLayout.currentIndex = 1;
+ setupWizard.startClientCOnfig(user, address)
}
function showSignIn(username) {
- if (contentLayout.currentIndex === 1)
- return;
- contentWrapper.showSignIn(username);
+ contentLayout.currentIndex = 1;
+ setupWizard.startLogin(username)
}
+
function showWebViewOverlay(url) {
webViewOverlay.visible = true;
webViewOverlay.url = url;
}
+ function layoutForUserCount(userCount) {
+ if (userCount === 0) {
+ showSignIn("");
+ return;
+ }
+
+ const u = Backend.users.get(0);
+ if (!u) {
+ console.trace();
+ console.log("empty user");
+ setupWizard.start();
+ return;
+ }
+
+ if ((userCount === 1) && (u.state === EUserState.SignedOut)) {
+ setupWizard.startLogin(u.primaryEmailOrUsername());
+ }
+ }
+
colorScheme: ProtonStyle.currentStyle
height: _defaultHeight
minimumWidth: _defaultWidth
@@ -72,10 +89,8 @@ ApplicationWindow {
function onRowsAboutToBeRemoved(parent, first, last) {
for (let i = first; i <= last; i++) {
const user = Backend.users.get(i);
- if (setupGuide.user === user) {
- setupGuide.user = null;
- contentLayout._showSetup = false;
- return;
+ if (setupWizard.user === user) {
+ setupWizard.closeWizard();
}
}
}
@@ -94,13 +109,6 @@ ApplicationWindow {
target: Backend.users
}
Connections {
- function onLoginFinished(index, wasSignedOut) {
- // const user = Backend.users.get(index);
- // if (user && !wasSignedOut) {
- // root.showSetup(user, user.addresses[0]);
- // }
- // console.debug("Login finished", index);
- }
function onSelectUser(userID, forceShowWindow) {
contentWrapper.selectUser(userID);
if (forceShowWindow) {
@@ -121,33 +129,19 @@ ApplicationWindow {
target: Backend
}
+
+ Connections {
+ function onCountChanged(count) {
+ layoutForUserCount(count)
+ }
+
+ target: Backend.users
+ }
StackLayout {
id: contentLayout
- property bool _showSetup: false
-
anchors.fill: parent
- currentIndex: {
- // show welcome when there are no users
- if (Backend.users.count === 0) {
- setupWizard.start();
- return 0;
- }
- const u = Backend.users.get(0);
- if (!u) {
- console.trace();
- console.log("empty user");
- return 1;
- }
- if ((Backend.users.count === 1) && (u.state === EUserState.SignedOut)) {
- showSignIn(u.primaryEmailOrUsername());
- return 0;
- }
- if (contentLayout._showSetup) {
- return 2;
- }
- return 0;
- }
+ currentIndex: 0
ContentWrapper {
// 0
@@ -169,33 +163,23 @@ ApplicationWindow {
onShowSetupGuide: function (user, address) {
setupWizard.startClientConfig(user, address);
}
- onShowSetupWizard: {
- setupWizard.start();
+ onShowSignIn: function(username) {
+ root.showSignIn(username)
}
}
- WelcomeGuide {
- Layout.fillHeight: true
- Layout.fillWidth: true // 1
- colorScheme: root.colorScheme
- }
- SetupGuide {
- // 2
- id: setupGuide
- Layout.fillHeight: true
- Layout.fillWidth: true
+
+ SetupWizard {
+ id: setupWizard
+ Layout.fillWidth: true;
+ Layout.fillHeight: true;
colorScheme: root.colorScheme
- onDismissed: {
- root.showSetup(null, "");
- }
- onFinished: {
- // TODO: Do not close window. Trigger Backend to check that
- // there is a successfully connected client. Then Backend
- // should send another signal to close the setup guide.
- root.showSetup(null, "");
+ onWizardEnded: {
+ contentLayout.currentIndex = 0
}
}
}
+
WebView {
id: webViewOverlay
anchors.fill: parent
@@ -204,12 +188,6 @@ ApplicationWindow {
url: ""
visible: false
}
- SetupWizard {
- id: setupWizard
- anchors.fill: parent
- colorScheme: root.colorScheme
- visible: false
- }
NotificationPopups {
colorScheme: root.colorScheme
mainWindow: root
@@ -219,4 +197,8 @@ ApplicationWindow {
id: splashScreen
colorScheme: root.colorScheme
}
+
+ Component.onCompleted: {
+ layoutForUserCount(Backend.users.count)
+ }
}
diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/SetupGuide.qml b/internal/frontend/bridge-gui/bridge-gui/qml/SetupGuide.qml
deleted file mode 100644
index 4cdfe43f..00000000
--- a/internal/frontend/bridge-gui/bridge-gui/qml/SetupGuide.qml
+++ /dev/null
@@ -1,293 +0,0 @@
-// Copyright (c) 2023 Proton AG
-// This file is part of Proton Mail Bridge.
-// Proton Mail Bridge is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-// Proton Mail Bridge is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with Proton Mail Bridge. If not, see .
-import QtQuick
-import QtQuick.Layouts
-import QtQuick.Controls
-import QtQuick.Controls.impl
-import Proton
-
-Item {
- id: root
-
- property string address
- property ColorScheme colorScheme
- property var user
-
- signal dismissed
- signal finished
-
- function reset() {
- guidePages.currentIndex = 0;
- clientList.currentIndex = -1;
- actionList.currentIndex = -1;
- }
- function setupAction(actionID, clientID) {
- if (user) {
- user.setupGuideSeen = true;
- }
- switch (actionID) {
- case -1:
- root.dismissed();
- break; // dismiss
- case 0 // automatic
- :
- if (user) {
- switch (clientID) {
- case 0:
- root.user.configureAppleMail(root.address);
- Backend.notifyAutoconfigClicked("AppleMail");
- break;
- }
- }
- root.finished();
- break;
- case 1 // manual
- :
- let clientObj = clients.get(clientID);
- if (clientObj !== undefined && clientObj.link !== "") {
- Qt.openUrlExternally(clientObj.link);
- Backend.notifyKBArticleClicked(clientObj.link);
- } else {
- console.log("unexpected client index", actionID, clientID);
- }
- root.finished();
- break;
- default:
- console.log("unexpected client setup action", actionID, clientID);
- }
- }
-
- implicitHeight: children[0].implicitHeight
- implicitWidth: children[0].implicitWidth
-
- ListModel {
- id: clients
-
- property bool haveAutoSetup: true
- property string iconSource: "/qml/icons/ic-apple-mail.svg"
- property string link: "https://proton.me/support/protonmail-bridge-clients-apple-mail"
- property string name: "Apple Mail"
-
- Component.onCompleted: {
- if (Backend.goos === "darwin") {
- append({
- "name": "Apple Mail",
- "iconSource": "/qml/icons/ic-apple-mail.svg",
- "haveAutoSetup": true,
- "link": "https://proton.me/support/protonmail-bridge-clients-apple-mail"
- });
- append({
- "name": "Microsoft Outlook",
- "iconSource": "/qml/icons/ic-microsoft-outlook.svg",
- "haveAutoSetup": false,
- "link": "https://proton.me/support/protonmail-bridge-clients-macos-outlook-2019"
- });
- }
- if (Backend.goos === "windows") {
- append({
- "name": "Microsoft Outlook",
- "iconSource": "/qml/icons/ic-microsoft-outlook.svg",
- "haveAutoSetup": false,
- "link": "https://proton.me/support/protonmail-bridge-clients-windows-outlook-2019"
- });
- }
- append({
- "name": "Mozilla Thunderbird",
- "iconSource": "/qml/icons/ic-mozilla-thunderbird.svg",
- "haveAutoSetup": false,
- "link": "https://proton.me/support/protonmail-bridge-clients-windows-thunderbird"
- });
- append({
- "name": "Other",
- "iconSource": "/qml/icons/ic-other-mail-clients.svg",
- "haveAutoSetup": false,
- "link": "https://proton.me/support/protonmail-bridge-configure-client"
- });
- }
- }
- Rectangle {
- anchors.fill: root
- color: root.colorScheme.background_norm
- }
- StackLayout {
- id: guidePages
- anchors.bottomMargin: 70
- anchors.fill: parent
- anchors.leftMargin: 80
- anchors.rightMargin: 80
- anchors.topMargin: 30
-
- ColumnLayout {
- // 0: Client selection
- id: clientView
-
- property int columnWidth: 268
-
- Layout.fillHeight: true
- spacing: 8
-
- Label {
- colorScheme: root.colorScheme
- text: qsTr("Setting up email client")
- type: Label.LabelType.Heading
- }
- Label {
- color: root.colorScheme.text_weak
- colorScheme: root.colorScheme
- text: address
- type: Label.LabelType.Lead
- }
- RowLayout {
- Layout.topMargin: 32 - clientView.spacing
- spacing: 24
-
- ColumnLayout {
- id: clientColumn
- Layout.alignment: Qt.AlignTop
-
- Label {
- id: labelA
- colorScheme: root.colorScheme
- text: qsTr("Choose an email client")
- type: Label.LabelType.Body_semibold
- }
- ListView {
- id: clientList
- Layout.fillHeight: true
- model: clients
- width: clientView.columnWidth
-
- delegate: Item {
- implicitHeight: clientRow.height
- implicitWidth: clientRow.width
-
- ColumnLayout {
- id: clientRow
- width: clientList.width
-
- RowLayout {
- Layout.bottomMargin: 12
- Layout.leftMargin: 16
- Layout.rightMargin: 16
- Layout.topMargin: 12
-
- ColorImage {
- height: 36
- source: model.iconSource
- sourceSize.height: 36
- }
- Label {
- Layout.leftMargin: 12
- colorScheme: root.colorScheme
- text: model.name
- type: Label.LabelType.Body
- }
- }
- Rectangle {
- Layout.fillWidth: true
- Layout.preferredHeight: 1
- color: root.colorScheme.border_weak
- }
- }
- MouseArea {
- anchors.fill: parent
- cursorShape: Qt.PointingHandCursor
-
- onClicked: {
- clientList.currentIndex = index;
- if (!model.haveAutoSetup) {
- root.setupAction(1, index);
- }
- }
- }
- }
- highlight: Rectangle {
- color: root.colorScheme.interaction_default_active
- radius: ProtonStyle.context_item_radius
- }
- }
- }
- ColumnLayout {
- id: actionColumn
- Layout.alignment: Qt.AlignTop
- visible: clientList.currentIndex >= 0 && clients.get(clientList.currentIndex).haveAutoSetup
-
- Label {
- colorScheme: root.colorScheme
- text: qsTr("Choose configuration mode")
- type: Label.LabelType.Body_semibold
- }
- ListView {
- id: actionList
- Layout.fillHeight: true
- model: [qsTr("Configure automatically"), qsTr("Configure manually")]
- width: clientView.columnWidth
-
- delegate: Item {
- implicitHeight: children[0].height
- implicitWidth: children[0].width
-
- ColumnLayout {
- width: actionList.width
-
- Label {
- Layout.bottomMargin: 20
- Layout.leftMargin: 16
- Layout.rightMargin: 16
- Layout.topMargin: 20
- colorScheme: root.colorScheme
- text: modelData
- type: Label.LabelType.Body
- }
- Rectangle {
- Layout.fillWidth: true
- Layout.preferredHeight: 1
- color: root.colorScheme.border_weak
- }
- }
- MouseArea {
- anchors.fill: parent
- cursorShape: Qt.PointingHandCursor
-
- onClicked: {
- actionList.currentIndex = index;
- root.setupAction(index, clientList.currentIndex);
- }
- }
- }
- highlight: Rectangle {
- color: root.colorScheme.interaction_default_active
- radius: ProtonStyle.context_item_radius
- }
- }
- }
- }
- Item {
- Layout.fillHeight: true
- }
- Button {
- colorScheme: root.colorScheme
- flat: true
- text: qsTr("Set up later")
-
- onClicked: {
- root.setupAction(-1, -1);
- if (user) {
- user.setupGuideSeen = true;
- }
- root.dismissed();
- }
- }
- }
- }
-}
diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/SetupWizard.qml b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/SetupWizard.qml
index 7d9bf352..36391627 100644
--- a/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/SetupWizard.qml
+++ b/internal/frontend/bridge-gui/bridge-gui/qml/SetupWizard/SetupWizard.qml
@@ -33,6 +33,8 @@ Item {
property var user
property string address
+ signal wizardEnded()
+
function clientIconSource() {
switch (client) {
case SetupWizard.Client.AppleMail:
@@ -66,7 +68,7 @@ Item {
}
function closeWizard() {
- root.visible = false;
+ wizardEnded()
}
function showOutlookSelector() {
@@ -92,13 +94,14 @@ Item {
rightContent.currentIndex = 2;
}
- function startLogin() {
+ function startLogin(username = "") {
root.visible = true;
rootStackLayout.currentIndex = 0;
root.address = "";
leftContent.showLogin();
rightContent.currentIndex = 1;
login.reset(true);
+ login.username = username;
}
function showClientWarning() {
diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/SignIn.qml b/internal/frontend/bridge-gui/bridge-gui/qml/SignIn.qml
deleted file mode 100644
index 35278df0..00000000
--- a/internal/frontend/bridge-gui/bridge-gui/qml/SignIn.qml
+++ /dev/null
@@ -1,413 +0,0 @@
-// Copyright (c) 2023 Proton AG
-// This file is part of Proton Mail Bridge.
-// Proton Mail Bridge is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-// Proton Mail Bridge is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with Proton Mail Bridge. If not, see .
-import QtQml
-import QtQuick
-import QtQuick.Layouts
-import QtQuick.Controls
-import QtQuick.Controls.impl
-import Proton
-
-FocusScope {
- id: root
-
- property ColorScheme colorScheme
- property alias currentIndex: stackLayout.currentIndex
- property alias username: usernameTextField.text
-
- function abort() {
- root.reset();
- Backend.loginAbort(usernameTextField.text);
- }
- function reset() {
- stackLayout.currentIndex = 0;
- loginNormalLayout.reset();
- login2FALayout.reset();
- login2PasswordLayout.reset();
- }
-
- implicitHeight: children[0].implicitHeight
- implicitWidth: children[0].implicitWidth
- state: "Page 1"
-
- states: [
- State {
- name: "Page 1"
-
- PropertyChanges {
- currentIndex: 0
- target: stackLayout
- }
- },
- State {
- name: "Page 2"
-
- PropertyChanges {
- currentIndex: 1
- target: stackLayout
- }
- },
- State {
- name: "Page 3"
-
- PropertyChanges {
- currentIndex: 2
- target: stackLayout
- }
- }
- ]
-
- StackLayout {
- id: stackLayout
- function loginFailed() {
- signInButton.loading = false;
- usernameTextField.enabled = true;
- usernameTextField.error = true;
- passwordTextField.enabled = true;
- passwordTextField.error = true;
- }
-
- anchors.fill: parent
-
- Connections {
- function onLogin2FAError(_) {
- console.assert(stackLayout.currentIndex === 1, "Unexpected login2FAError");
- twoFAButton.loading = false;
- twoFactorPasswordTextField.enabled = true;
- twoFactorPasswordTextField.error = true;
- twoFactorPasswordTextField.errorString = qsTr("Your code is incorrect");
- twoFactorPasswordTextField.focus = true;
- }
- function onLogin2FAErrorAbort(_) {
- console.assert(stackLayout.currentIndex === 1, "Unexpected login2FAErrorAbort");
- root.reset();
- errorLabel.text = qsTr("Incorrect login credentials. Please try again.");
- }
- function onLogin2FARequested(username) {
- console.assert(stackLayout.currentIndex === 0, "Unexpected login2FARequested");
- twoFactorUsernameLabel.text = username;
- stackLayout.currentIndex = 1;
- twoFactorPasswordTextField.focus = true;
- }
- function onLogin2PasswordError(_) {
- console.assert(stackLayout.currentIndex === 2, "Unexpected login2PasswordError");
- secondPasswordButton.loading = false;
- secondPasswordTextField.enabled = true;
- secondPasswordTextField.error = true;
- secondPasswordTextField.errorString = qsTr("Your mailbox password is incorrect");
- secondPasswordTextField.focus = true;
- }
- function onLogin2PasswordErrorAbort(_) {
- console.assert(stackLayout.currentIndex === 2, "Unexpected login2PasswordErrorAbort");
- root.reset();
- errorLabel.text = qsTr("Incorrect login credentials. Please try again.");
- }
- function onLogin2PasswordRequested() {
- console.assert(stackLayout.currentIndex === 0 || stackLayout.currentIndex === 1, "Unexpected login2PasswordRequested");
- stackLayout.currentIndex = 2;
- secondPasswordTextField.focus = true;
- }
- function onLoginAlreadyLoggedIn(_) {
- stackLayout.currentIndex = 0;
- root.reset();
- }
- function onLoginConnectionError(_) {
- if (stackLayout.currentIndex === 0) {
- stackLayout.loginFailed();
- }
- }
- function onLoginFinished(_) {
- stackLayout.currentIndex = 0;
- root.reset();
- }
- function onLoginFreeUserError() {
- console.assert(stackLayout.currentIndex === 0, "Unexpected loginFreeUserError");
- stackLayout.loginFailed();
- }
- function onLoginUsernamePasswordError(errorMsg) {
- console.assert(stackLayout.currentIndex === 0, "Unexpected loginUsernamePasswordError");
- stackLayout.loginFailed();
- if (errorMsg !== "")
- errorLabel.text = errorMsg;
- else
- errorLabel.text = qsTr("Incorrect login credentials");
- }
-
- target: Backend
- }
- ColumnLayout {
- id: loginNormalLayout
- function reset() {
- signInButton.loading = false;
- errorLabel.text = "";
- usernameTextField.enabled = true;
- usernameTextField.error = false;
- usernameTextField.errorString = "";
- usernameTextField.focus = true;
- passwordTextField.enabled = true;
- passwordTextField.error = false;
- passwordTextField.errorString = "";
- passwordTextField.text = "";
- }
-
- spacing: 0
-
- Label {
- Layout.alignment: Qt.AlignHCenter
- Layout.topMargin: 16
- colorScheme: root.colorScheme
- text: qsTr("Sign in")
- type: Label.LabelType.Title
- }
- Label {
- id: subTitle
- Layout.alignment: Qt.AlignHCenter
- Layout.topMargin: 8
- color: root.colorScheme.text_weak
- colorScheme: root.colorScheme
- text: qsTr("Enter your Proton Account details.")
- type: Label.LabelType.Body
- }
- RowLayout {
- Layout.fillWidth: true
- Layout.topMargin: 36
- spacing: 0
- visible: errorLabel.text.length > 0
-
- ColorImage {
- color: root.colorScheme.signal_danger
- height: errorLabel.lineHeight
- source: "/qml/icons/ic-exclamation-circle-filled.svg"
- sourceSize.height: errorLabel.lineHeight
- }
- Label {
- id: errorLabel
- Layout.fillWidth: true
- Layout.leftMargin: 4
- color: root.colorScheme.signal_danger
- colorScheme: root.colorScheme
- type: root.error ? Label.LabelType.Caption_semibold : Label.LabelType.Caption
- wrapMode: Text.WordWrap
- }
- }
- TextField {
- id: usernameTextField
- Layout.fillWidth: true
- Layout.topMargin: 24
- colorScheme: root.colorScheme
- focus: true
- label: qsTr("Email or username")
- validateOnEditingFinished: false
- validator: function (str) {
- if (str.length === 0) {
- return qsTr("Enter email or username");
- }
- }
-
- onAccepted: passwordTextField.forceActiveFocus()
- onTextChanged: {
- // remove "invalid username / password error"
- if (error || errorLabel.text.length > 0) {
- errorLabel.text = "";
- usernameTextField.error = false;
- passwordTextField.error = false;
- }
- }
- }
- TextField {
- id: passwordTextField
- Layout.fillWidth: true
- Layout.topMargin: 8
- colorScheme: root.colorScheme
- echoMode: TextInput.Password
- label: qsTr("Password")
- validateOnEditingFinished: false
- validator: function (str) {
- if (str.length === 0) {
- return qsTr("Enter password");
- }
- }
-
- onAccepted: signInButton.checkAndSignIn()
- onTextChanged: {
- // remove "invalid username / password error"
- if (error || errorLabel.text.length > 0) {
- errorLabel.text = "";
- usernameTextField.error = false;
- passwordTextField.error = false;
- }
- }
- }
- Button {
- id: signInButton
- function checkAndSignIn() {
- usernameTextField.validate();
- passwordTextField.validate();
- if (usernameTextField.error || passwordTextField.error) {
- return;
- }
- usernameTextField.enabled = false;
- passwordTextField.enabled = false;
- loading = true;
- Backend.login(usernameTextField.text, Qt.btoa(passwordTextField.text));
- }
-
- Layout.fillWidth: true
- Layout.topMargin: 24
- colorScheme: root.colorScheme
- enabled: !loading
- text: loading ? qsTr("Signing in") : qsTr("Sign in")
-
- onClicked: {
- checkAndSignIn();
- }
- }
- Label {
- Layout.alignment: Qt.AlignHCenter
- Layout.topMargin: 24
- colorScheme: root.colorScheme
- text: link("https://proton.me/mail/pricing", qsTr("Create or upgrade your account"))
- textFormat: Text.StyledText
- type: Label.LabelType.Body
-
- onLinkActivated: {
- Qt.openUrlExternally(link);
- }
- }
- }
- ColumnLayout {
- id: login2FALayout
- function reset() {
- twoFAButton.loading = false;
- twoFactorPasswordTextField.enabled = true;
- twoFactorPasswordTextField.error = false;
- twoFactorPasswordTextField.errorString = "";
- twoFactorPasswordTextField.text = "";
- }
-
- spacing: 0
-
- Label {
- Layout.alignment: Qt.AlignCenter
- Layout.topMargin: 16
- colorScheme: root.colorScheme
- text: qsTr("Two-factor authentication")
- type: Label.LabelType.Heading
- }
- Label {
- id: twoFactorUsernameLabel
- Layout.alignment: Qt.AlignCenter
- Layout.topMargin: 8
- color: root.colorScheme.text_weak
- colorScheme: root.colorScheme
- type: Label.LabelType.Lead
- }
- TextField {
- id: twoFactorPasswordTextField
- Layout.fillWidth: true
- Layout.topMargin: 32
- assistiveText: qsTr("Enter the 6-digit code")
- colorScheme: root.colorScheme
- label: qsTr("Two-factor code")
- validateOnEditingFinished: false
- validator: function (str) {
- if (str.length === 0) {
- return qsTr("Enter the 6-digit code");
- }
- }
-
- onAccepted: {
- twoFAButton.onClicked();
- }
- onTextChanged: {
- if (text.length >= 6) {
- twoFAButton.onClicked();
- }
- }
- }
- Button {
- id: twoFAButton
- Layout.fillWidth: true
- Layout.topMargin: 24
- colorScheme: root.colorScheme
- enabled: !loading
- text: loading ? qsTr("Authenticating") : qsTr("Authenticate")
-
- onClicked: {
- twoFactorPasswordTextField.validate();
- if (twoFactorPasswordTextField.error) {
- return;
- }
- twoFactorPasswordTextField.enabled = false;
- loading = true;
- Backend.login2FA(usernameTextField.text, Qt.btoa(twoFactorPasswordTextField.text));
- }
- }
- }
- ColumnLayout {
- id: login2PasswordLayout
- function reset() {
- secondPasswordButton.loading = false;
- secondPasswordTextField.enabled = true;
- secondPasswordTextField.error = false;
- secondPasswordTextField.errorString = "";
- secondPasswordTextField.text = "";
- }
-
- spacing: 0
-
- Label {
- Layout.alignment: Qt.AlignCenter
- Layout.topMargin: 16
- colorScheme: root.colorScheme
- text: qsTr("Unlock your mailbox")
- type: Label.LabelType.Heading
- }
- TextField {
- id: secondPasswordTextField
- Layout.fillWidth: true
- Layout.topMargin: 8 + implicitHeight + 24 + subTitle.implicitHeight
- colorScheme: root.colorScheme
- echoMode: TextInput.Password
- label: qsTr("Mailbox password")
- validateOnEditingFinished: false
- validator: function (str) {
- if (str.length === 0) {
- return qsTr("Enter password");
- }
- }
-
- onAccepted: {
- secondPasswordButton.onClicked();
- }
- }
- Button {
- id: secondPasswordButton
- Layout.fillWidth: true
- Layout.topMargin: 24
- colorScheme: root.colorScheme
- enabled: !loading
- text: loading ? qsTr("Unlocking") : qsTr("Unlock")
-
- onClicked: {
- secondPasswordTextField.validate();
- if (secondPasswordTextField.error) {
- return;
- }
- secondPasswordTextField.enabled = false;
- loading = true;
- Backend.login2Password(usernameTextField.text, Qt.btoa(secondPasswordTextField.text));
- }
- }
- }
- }
-}
diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/WelcomeGuide.qml b/internal/frontend/bridge-gui/bridge-gui/qml/WelcomeGuide.qml
deleted file mode 100644
index 94df5dec..00000000
--- a/internal/frontend/bridge-gui/bridge-gui/qml/WelcomeGuide.qml
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright (c) 2023 Proton AG
-// This file is part of Proton Mail Bridge.
-// Proton Mail Bridge is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-// Proton Mail Bridge is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-// You should have received a copy of the GNU General Public License
-// along with Proton Mail Bridge. If not, see .
-import QtQml
-import QtQuick
-import QtQuick.Layouts
-import QtQuick.Controls
-import Proton
-
-Item {
- id: root
-
- property ColorScheme colorScheme
-
- implicitHeight: children[0].implicitHeight
- implicitWidth: children[0].implicitWidth
-
- RowLayout {
- anchors.fill: parent
- spacing: 0
-
- states: [
- State {
- name: "Page 1"
-
- PropertyChanges {
- currentIndex: 0
- target: signInItem
- }
- },
- State {
- name: "Page 2"
-
- PropertyChanges {
- currentIndex: 1
- target: signInItem
- }
- },
- State {
- name: "Page 3"
-
- PropertyChanges {
- currentIndex: 2
- target: signInItem
- }
- }
- ]
-
- Rectangle {
- Layout.fillHeight: true
- Layout.fillWidth: true
- color: root.colorScheme.background_norm
- implicitHeight: children[0].implicitHeight
- implicitWidth: children[0].implicitWidth
- visible: signInItem.currentIndex === 0
-
- GridLayout {
- anchors.fill: parent
- columnSpacing: 0
- columns: 3
- rowSpacing: 0
-
- // top margin
- Item {
- Layout.columnSpan: 3
- Layout.fillWidth: true
-
- // Using binding component here instead of direct binding to avoid binding loop during construction of element
- Binding on Layout.preferredHeight {
- value: (parent.height - welcomeContentItem.height) / 4
- }
- }
-
- // left margin
- Item {
- Layout.fillWidth: true
- Layout.maximumWidth: 80
- Layout.minimumWidth: 48
- Layout.preferredHeight: welcomeContentItem.height
- }
- ColumnLayout {
- id: welcomeContentItem
- Layout.fillWidth: true
- spacing: 0
-
- Image {
- Layout.alignment: Qt.AlignHCenter
- Layout.topMargin: 16
- source: "/qml/icons/img-welcome.svg"
- sourceSize.height: 148
- sourceSize.width: 264
- }
- Label {
- Layout.alignment: Qt.AlignHCenter
- Layout.fillWidth: true
- Layout.topMargin: 16
- colorScheme: root.colorScheme
- horizontalAlignment: Text.AlignHCenter
- text: qsTr("Welcome to\nProton Mail Bridge")
- type: Label.LabelType.Heading
- }
- Label {
- id: longTextLabel
- Layout.alignment: Qt.AlignHCenter
- Layout.fillWidth: true
- Layout.preferredWidth: 320
- Layout.topMargin: 16
- colorScheme: root.colorScheme
- horizontalAlignment: Text.AlignHCenter
- text: qsTr("Add your Proton Mail account to securely access and manage your messages in your favorite email client. Bridge runs in the background and encrypts and decrypts your messages seamlessly.")
- type: Label.LabelType.Body
- wrapMode: Text.WordWrap
- }
- }
-
- // Right margin
- Item {
- Layout.fillWidth: true
- Layout.maximumWidth: 80
- Layout.minimumWidth: 48
- Layout.preferredHeight: welcomeContentItem.height
- }
-
- // bottom margin
- Item {
- Layout.columnSpan: 3
- Layout.fillHeight: true
- Layout.fillWidth: true
- implicitHeight: children[0].implicitHeight + children[0].anchors.bottomMargin + children[0].anchors.topMargin
- implicitWidth: children[0].implicitWidth
-
- Image {
- id: logoImage
- anchors.bottom: parent.bottom
- anchors.bottomMargin: 48
- anchors.horizontalCenter: parent.horizontalCenter
- anchors.topMargin: 48
- source: colorScheme.logo_img
- sourceSize.height: 25
- sourceSize.width: 200
- }
- }
- }
- }
- Rectangle {
- Layout.fillHeight: true
- Layout.fillWidth: true
- color: (signInItem.currentIndex == 0) ? root.colorScheme.background_weak : root.colorScheme.background_norm
- implicitHeight: children[0].implicitHeight
- implicitWidth: children[0].implicitWidth
-
- RowLayout {
- anchors.fill: parent
- spacing: 0
-
- Item {
- Layout.fillHeight: true
- Layout.fillWidth: true
- Layout.preferredWidth: signInItem.currentIndex == 0 ? 0 : parent.width / 4
- implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
- implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
-
- Button {
- anchors.bottom: parent.bottom
- anchors.bottomMargin: 80
- anchors.left: parent.left
- anchors.leftMargin: 80
- anchors.rightMargin: 80
- anchors.topMargin: 80
- colorScheme: root.colorScheme
- secondary: true
- text: qsTr("Back")
- visible: signInItem.currentIndex != 0
-
- onClicked: {
- signInItem.abort();
- }
- }
- }
- GridLayout {
- Layout.fillHeight: true
- Layout.fillWidth: true
- columnSpacing: 0
- columns: 3
- rowSpacing: 0
-
- // top margin
- Item {
- Layout.columnSpan: 3
- Layout.fillWidth: true
-
- // Using binding component here instead of direct binding to avoid binding loop during construction of element
- Binding on Layout.preferredHeight {
- value: (parent.height - signInItem.height) / 4
- }
- }
-
- // left margin
- Item {
- Layout.fillWidth: true
- Layout.maximumWidth: 80
- Layout.minimumWidth: 48
- Layout.preferredHeight: signInItem.height
- }
- SignIn {
- id: signInItem
- Layout.fillWidth: true
- Layout.preferredWidth: 320
- colorScheme: root.colorScheme
- focus: true
- username: Backend.users.count === 1 && Backend.users.get(0) && (Backend.users.get(0).state === EUserState.SignedOut) ? Backend.users.get(0).username : ""
- }
-
- // Right margin
- Item {
- Layout.fillWidth: true
- Layout.maximumWidth: 80
- Layout.minimumWidth: 48
- Layout.preferredHeight: signInItem.height
- }
-
- // bottom margin
- Item {
- Layout.columnSpan: 3
- Layout.fillHeight: true
- Layout.fillWidth: true
- }
- }
- Item {
- Layout.fillHeight: true
- Layout.preferredWidth: signInItem.currentIndex === 0 ? 0 : parent.width / 4
- }
- }
- }
- }
-}