diff --git a/internal/app/bridge/bridge.go b/internal/app/bridge/bridge.go index 44b0e06..71cd027 100644 --- a/internal/app/bridge/bridge.go +++ b/internal/app/bridge/bridge.go @@ -269,6 +269,8 @@ func loadCache(b *base.Base) (cache.Cache, error) { path = customPath } else { path = b.Cache.GetDefaultMessageCacheDir() + // Store path so it will allways persist if default location will be changed in new version. + b.Settings.Set(settings.CacheLocationKey, path) } return cache.NewOnDiskCache(path, compressor, cache.Options{ diff --git a/internal/frontend/qml/BridgeTest/UserControl.qml b/internal/frontend/qml/BridgeTest/UserControl.qml index 0c3c755..d714f32 100644 --- a/internal/frontend/qml/BridgeTest/UserControl.qml +++ b/internal/frontend/qml/BridgeTest/UserControl.qml @@ -162,7 +162,7 @@ ColumnLayout { enabled: user !== undefined //&& user.isLoginRequested && !user.isLogin2FARequested && !user.isLogin2PasswordRequested onClicked: { - root.backend.login2FARequested() + root.backend.login2FARequested(user.username) user.isLogin2FARequested = true } } diff --git a/internal/frontend/qml/Bridge_test.qml b/internal/frontend/qml/Bridge_test.qml index ac1f36d..0eebb69 100644 --- a/internal/frontend/qml/Bridge_test.qml +++ b/internal/frontend/qml/Bridge_test.qml @@ -636,7 +636,7 @@ Window { signal loginUsernamePasswordError(string errorMsg) signal loginFreeUserError() signal loginConnectionError(string errorMsg) - signal login2FARequested() + signal login2FARequested(string username) signal login2FAError(string errorMsg) signal login2FAErrorAbort(string errorMsg) signal login2PasswordRequested() @@ -799,7 +799,7 @@ Window { console.debug("<- loginConnectionError") } onLogin2FARequested: { - console.debug("<- login2FARequested") + console.debug("<- login2FARequested", username) } onLogin2FAError: { console.debug("<- login2FAError") diff --git a/internal/frontend/qml/GeneralSettings.qml b/internal/frontend/qml/GeneralSettings.qml index 202f4bc..e1bdada 100644 --- a/internal/frontend/qml/GeneralSettings.qml +++ b/internal/frontend/qml/GeneralSettings.qml @@ -50,8 +50,8 @@ SettingsView { SettingsItem { id: autostart colorScheme: root.colorScheme - text: qsTr("Automatically start Bridge") - description: qsTr("The app will autostart everytime you reset your device.") + text: qsTr("Open on startup") + description: qsTr("Bridge will open upon startup.") type: SettingsItem.Toggle checked: root.backend.isAutostartOn onClicked: { @@ -159,7 +159,7 @@ SettingsView { colorScheme: root.colorScheme text: qsTr("Local cache") actionText: qsTr("Configure") - description: qsTr("Configure Bridge's local cache settings.") + description: qsTr("Configure Bridge's local cache.") type: SettingsItem.Button onClicked: root.parent.showLocalCacheSettings() diff --git a/internal/frontend/qml/LocalCacheSettings.qml b/internal/frontend/qml/LocalCacheSettings.qml index 5701cc2..69583b0 100644 --- a/internal/frontend/qml/LocalCacheSettings.qml +++ b/internal/frontend/qml/LocalCacheSettings.qml @@ -39,7 +39,7 @@ SettingsView { Label { colorScheme: root.colorScheme - text: qsTr("Bridge caches your encrypted messages localy to optimise the communication with the local client. Disabling this feature might have a nevative impact on performance.") + text: qsTr("Bridge stores your encrypted messages locally to optimize communication with the local client.") type: Label.Body color: root.colorScheme.text_weak Layout.fillWidth: true @@ -50,7 +50,7 @@ SettingsView { SettingsItem { colorScheme: root.colorScheme text: qsTr("Enable local cache") - description: "When enabled messages are stored on disk." // TODO: wrong text in wireframe + description: qsTr("Recommended for optimal performance.") type: SettingsItem.Toggle checked: root._diskCacheEnabled onClicked: root._diskCacheEnabled = !root._diskCacheEnabled @@ -145,5 +145,7 @@ SettingsView { root._diskCachePath = path.replace(pattern, "") } - Component.onCompleted: root.setDefaultValues() + onVisibleChanged: { + root.setDefaultValues() + } } diff --git a/internal/frontend/qml/Notifications/Notifications.qml b/internal/frontend/qml/Notifications/Notifications.qml index becb021..01d3a4d 100644 --- a/internal/frontend/qml/Notifications/Notifications.qml +++ b/internal/frontend/qml/Notifications/Notifications.qml @@ -769,7 +769,7 @@ QtObject { property Notification resetBridge: Notification { text: qsTr("Reset Bridge?") - description: qsTr("This will clear your accounts, preferences, and cached data. You will need to reconfigure your email client. Bridge will automatically restart") + description: qsTr("This will clear your accounts, preferences, and cached data. You will need to reconfigure your email client. Bridge will automatically restart.") type: Notification.NotificationType.Warning group: Notifications.Group.Configuration | Notifications.Group.Dialogs diff --git a/internal/frontend/qml/SignIn.qml b/internal/frontend/qml/SignIn.qml index ffc73fe..98ec746 100644 --- a/internal/frontend/qml/SignIn.qml +++ b/internal/frontend/qml/SignIn.qml @@ -73,7 +73,7 @@ Item { stackLayout.loginFailed() if (errorMsg!="") errorLabel.text = errorMsg - else errorLabel.text = qsTr("Your email and/or password are incorrect") + else errorLabel.text = qsTr("Incorrect login credentials") } onLoginFreeUserError: { @@ -89,6 +89,7 @@ Item { onLogin2FARequested: { console.assert(stackLayout.currentIndex == 0, "Unexpected login2FARequested") + twoFactorUsernameLabel.text = username stackLayout.currentIndex = 1 } onLogin2FAError: { @@ -289,7 +290,7 @@ Item { Label { colorScheme: root.colorScheme textFormat: Text.StyledText - text: link("https://protonmail.com/upgrade", qsTr("Create or upgrade your account")) + text: link("https://protonmail.com/signup", qsTr("Create or upgrade your account")) Layout.alignment: Qt.AlignHCenter Layout.topMargin: 24 type: Label.LabelType.Body @@ -323,13 +324,24 @@ Item { type: Label.LabelType.Heading } + Label { + colorScheme: root.colorScheme + id: twoFactorUsernameLabel + + Layout.alignment: Qt.AlignCenter + Layout.topMargin: 8 + type: Label.LabelType.Lead + color: root.colorScheme.text_weak + } + TextField { colorScheme: root.colorScheme id: twoFactorPasswordTextField - label: qsTr("Two-factor authentication code") + label: qsTr("Two-factor code") + assistiveText: qsTr("Enter the 6-digit code") Layout.fillWidth: true - Layout.topMargin: 8 + implicitHeight + 24 + subTitle.implicitHeight + Layout.topMargin: 32 onTextEdited: { if (error) { diff --git a/internal/frontend/qml/WelcomeGuide.qml b/internal/frontend/qml/WelcomeGuide.qml index eb54e9d..ca93647 100644 --- a/internal/frontend/qml/WelcomeGuide.qml +++ b/internal/frontend/qml/WelcomeGuide.qml @@ -89,7 +89,7 @@ Item { Label { colorScheme: root.colorScheme - text: qsTr("Welcome to\nProtonMail Bridge") + text: qsTr("Welcome to\nProton Mail Bridge") Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true Layout.topMargin: 16 diff --git a/internal/frontend/qt/frontend_users.go b/internal/frontend/qt/frontend_users.go index c3de074..24c328e 100644 --- a/internal/frontend/qt/frontend_users.go +++ b/internal/frontend/qt/frontend_users.go @@ -39,6 +39,12 @@ func (f *FrontendQt) login(username, password string) { f.authClient, f.auth, err = f.bridge.Login(username, f.password) if err != nil { + if err == pmapi.ErrPasswordWrong { + // Remove error message since it is hardcodded in QML. + f.qml.LoginUsernamePasswordError("") + f.loginClean() + return + } if err == pmapi.ErrPaidPlanRequired { f.qml.LoginFreeUserError() f.loginClean() @@ -50,7 +56,7 @@ func (f *FrontendQt) login(username, password string) { } if f.auth.HasTwoFactor() { - f.qml.Login2FARequested() + f.qml.Login2FARequested(username) return } if f.auth.HasMailboxPassword() { diff --git a/internal/frontend/qt/qml_backend.go b/internal/frontend/qt/qml_backend.go index 7e52058..e1f9c5a 100644 --- a/internal/frontend/qt/qml_backend.go +++ b/internal/frontend/qt/qml_backend.go @@ -57,7 +57,7 @@ type QMLBackend struct { _ func(errorMsg string) `signal:"loginUsernamePasswordError"` _ func() `signal:"loginFreeUserError"` _ func(errorMsg string) `signal:"loginConnectionError"` - _ func() `signal:"login2FARequested"` + _ func(username string) `signal:"login2FARequested"` _ func(errorMsg string) `signal:"login2FAError"` _ func(errorMsg string) `signal:"login2FAErrorAbort"` _ func() `signal:"login2PasswordRequested"` diff --git a/pkg/pmapi/errors.go b/pkg/pmapi/errors.go index 80c1ccd..89f911e 100644 --- a/pkg/pmapi/errors.go +++ b/pkg/pmapi/errors.go @@ -28,6 +28,7 @@ var ( ErrBad2FACodeTryAgain = errors.New("incorrect 2FA code: please try again") ErrPaidPlanRequired = errors.New("paid subscription plan is required") + ErrPasswordWrong = errors.New("wrong password") ) type ErrUnprocessableEntity struct { diff --git a/pkg/pmapi/response.go b/pkg/pmapi/response.go index 745d292..ff1bb8c 100644 --- a/pkg/pmapi/response.go +++ b/pkg/pmapi/response.go @@ -31,6 +31,7 @@ import ( const ( errCodeUpgradeApplication = 5003 + errCodePasswordWrong = 8002 errCodeAuthPaidPlanRequired = 10004 ) @@ -61,6 +62,8 @@ func (m *manager) catchAPIError(_ *resty.Client, res *resty.Response) error { if m.cfg.UpgradeApplicationHandler != nil { m.cfg.UpgradeApplicationHandler() } + case apiErr.Code == errCodePasswordWrong: + err = ErrPasswordWrong case apiErr.Code == errCodeAuthPaidPlanRequired: err = ErrPaidPlanRequired case res.StatusCode() == http.StatusUnprocessableEntity: