diff --git a/Makefile b/Makefile index c12e4766..eabc7706 100644 --- a/Makefile +++ b/Makefile @@ -292,7 +292,7 @@ run-debug: run-qml-preview: find internal/frontend/qml/ -iname '*qmlc' | xargs rm -f - cd internal/frontend/qml/ && qmlscene -verbose -I . -f Bridge_test.qml + bridge_preview internal/frontend/qml/Bridge_test.qml clean-frontend-qt: diff --git a/internal/frontend/qml/Bridge_test.qml b/internal/frontend/qml/Bridge_test.qml index f1fe4091..bab4b7b5 100644 --- a/internal/frontend/qml/Bridge_test.qml +++ b/internal/frontend/qml/Bridge_test.qml @@ -242,8 +242,8 @@ Window { // add one user on start - var haveUserOnStart = true - if (haveUserOnStart) { + var hasUserOnStart = true + if (hasUserOnStart) { var newUserObject = root.userComponent.createObject(root) newUserObject.username = "LerooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooyJenkins@protonmail.com" newUserObject.loggedIn = true @@ -584,6 +584,14 @@ Window { root.diskFull() } } + + Button { + text: "No keychain" + colorScheme: root.colorScheme + onClicked: { + root.hasNoKeychain() + } + } } } @@ -799,11 +807,14 @@ Window { signal bugReportSendSuccess() signal bugReportSendError() - property var availableKeychain: ["gnome-keyring", "pass"] - property string selectedKeychain - function selectKeychain(wantedKeychain){ - selectedKeychain = wantedKeychain + property var availableKeychain: ["gnome-keyring", "pass", "macos-keychain", "windows-credentials"] + property string currentKeychain: availableKeychain[0] + function changeKeychain(wantedKeychain){ + console.log("Changing keychain from", root.currentKeychain, "to", wantedKeychain) + root.currentKeychain = wantedKeychain + root.changeKeychainFinished() } + signal changeKeychainFinished() signal hasNoKeychain() signal noActiveKeyForRecipient(string email) diff --git a/internal/frontend/qml/ContentWrapper.qml b/internal/frontend/qml/ContentWrapper.qml index 98367e2d..66bf2e83 100644 --- a/internal/frontend/qml/ContentWrapper.qml +++ b/internal/frontend/qml/ContentWrapper.qml @@ -310,7 +310,7 @@ Item { } } - PortSettings { // 3 + KeychainSettings { // 3 colorScheme: root.colorScheme backend: root.backend @@ -319,7 +319,7 @@ Item { } } - SMTPSettings { // 4 + PortSettings { // 4 colorScheme: root.colorScheme backend: root.backend @@ -328,7 +328,16 @@ Item { } } - LocalCacheSettings { // 5 + SMTPSettings { // 5 + colorScheme: root.colorScheme + backend: root.backend + + onBack: { + rightContent.showGeneralSettings() + } + } + + LocalCacheSettings { // 6 colorScheme: root.colorScheme backend: root.backend notifications: root.notifications @@ -338,7 +347,7 @@ Item { } } - HelpView { // 6 + HelpView { // 7 colorScheme: root.colorScheme backend: root.backend @@ -347,7 +356,7 @@ Item { } } - BugReportView { // 7 + BugReportView { // 8 colorScheme: root.colorScheme backend: root.backend selectedAddress: { @@ -372,11 +381,12 @@ Item { function showSignIn () { rightContent.currentIndex = 1 } function showGeneralSettings () { rightContent.currentIndex = 2 } - function showPortSettings () { rightContent.currentIndex = 3 } - function showSMTPSettings () { rightContent.currentIndex = 4 } - function showLocalCacheSettings () { rightContent.currentIndex = 5 } - function showHelpView () { rightContent.currentIndex = 6 } - function showBugReport () { rightContent.currentIndex = 7 } + function showKeychainSettings () { rightContent.currentIndex = 3 } + function showPortSettings () { rightContent.currentIndex = 4 } + function showSMTPSettings () { rightContent.currentIndex = 5 } + function showLocalCacheSettings () { rightContent.currentIndex = 6 } + function showHelpView () { rightContent.currentIndex = 7 } + function showBugReport () { rightContent.currentIndex = 8 } Connections { target: root.backend diff --git a/internal/frontend/qml/GeneralSettings.qml b/internal/frontend/qml/GeneralSettings.qml index d9e2b1f4..1637b387 100644 --- a/internal/frontend/qml/GeneralSettings.qml +++ b/internal/frontend/qml/GeneralSettings.qml @@ -116,6 +116,20 @@ SettingsView { } } + SettingsItem { + id: keychains + visible: root._isAdvancedShown && root.backend.availableKeychain.length > 1 + colorScheme: root.colorScheme + text: qsTr("Change keychain") + description: qsTr("Change which keychain Bridge uses as default") + actionText: qsTr("Change") + type: SettingsItem.Button + checked: root.backend.isDoHEnabled + onClicked: root.parent.showKeychainSettings() + + Layout.fillWidth: true + } + SettingsItem { id: doh visible: root._isAdvancedShown diff --git a/internal/frontend/qml/KeychainSettings.qml b/internal/frontend/qml/KeychainSettings.qml new file mode 100644 index 00000000..00fc017d --- /dev/null +++ b/internal/frontend/qml/KeychainSettings.qml @@ -0,0 +1,116 @@ +// Copyright (c) 2022 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail 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. +// +// ProtonMail 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 ProtonMail Bridge. If not, see . + +import QtQuick 2.13 +import QtQuick.Layouts 1.12 +import QtQuick.Controls 2.13 +import QtQuick.Controls.impl 2.13 + +import Proton 4.0 + +SettingsView { + id: root + + fillHeight: false + + property bool _valuesChanged: keychainSelection.checkedButton && keychainSelection.checkedButton.text != root.backend.currentKeychain + + Label { + colorScheme: root.colorScheme + text: qsTr("Default keychain") + type: Label.Heading + Layout.fillWidth: true + } + + Label { + colorScheme: root.colorScheme + text: qsTr("Change which keychain Bridge uses as default") + type: Label.Body + color: root.colorScheme.text_weak + Layout.fillWidth: true + wrapMode: Text.WordWrap + } + + ColumnLayout { + spacing: 16 + + ButtonGroup{ id: keychainSelection } + + Repeater { + model: root.backend.availableKeychain + + RadioButton { + colorScheme: root.colorScheme + ButtonGroup.group: keychainSelection + text: modelData + } + } + } + + + Rectangle { + Layout.fillWidth: true + height: 1 + color: root.colorScheme.border_weak + } + + RowLayout { + spacing: 12 + + Button { + id: submitButton + colorScheme: root.colorScheme + text: qsTr("Save and restart") + enabled: root._valuesChanged + onClicked: { + root.backend.changeKeychain(keychainSelection.checkedButton.text) + } + } + + Button { + colorScheme: root.colorScheme + text: qsTr("Cancel") + onClicked: root.back() + secondary: true + } + + Connections { + target: root.backend + + onChangeKeychainFinished: { + submitButton.loading = false + root.back() + } + } + } + + onBack: { + root.setDefaultValues() + } + + function setDefaultValues(){ + for (var bi in keychainSelection.buttons){ + var button = keychainSelection.buttons[bi] + if (button.text == root.backend.currentKeychain) { + button.checked = true + break; + } + } + } + + Component.onCompleted: root.setDefaultValues() +} diff --git a/internal/frontend/qml/NotificationPopups.qml b/internal/frontend/qml/NotificationPopups.qml index 274fe145..3e239122 100644 --- a/internal/frontend/qml/NotificationPopups.qml +++ b/internal/frontend/qml/NotificationPopups.qml @@ -110,4 +110,9 @@ Item { colorScheme: root.colorScheme notification: root.notifications.deleteAccount } + + NotificationDialog { + colorScheme: root.colorScheme + notification: root.notifications.noKeychain + } } diff --git a/internal/frontend/qml/Notifications/Notifications.qml b/internal/frontend/qml/Notifications/Notifications.qml index f18da22e..cb4051dc 100644 --- a/internal/frontend/qml/Notifications/Notifications.qml +++ b/internal/frontend/qml/Notifications/Notifications.qml @@ -72,7 +72,8 @@ QtObject { root.disableLocalCache, root.enableLocalCache, root.resetBridge, - root.deleteAccount + root.deleteAccount, + root.noKeychain ] // Connection @@ -866,4 +867,31 @@ QtObject { } ] } + + property Notification noKeychain: Notification { + title: qsTr("No keychain available") + description: qsTr("Bridge is not able to detected a supported password manager (pass, gnome-keyring). Please install and setup supported password manager and restart the application.") + brief: title + icon: "./icons/ic-exclamation-circle-filled.svg" + type: Notification.NotificationType.Danger + group: Notifications.Group.Dialogs | Notifications.Group.Configuration + + Connections { + target: root.backend + + onHasNoKeychain: { + root.noKeychain.active = true + } + } + + action: [ + Action { + text: qsTr("Quit Bridge") + + onTriggered: { + root.backend.quit() + } + } + ] + } } diff --git a/internal/frontend/qt/frontend_settings.go b/internal/frontend/qt/frontend_settings.go index 2601fb8a..5fd8e481 100644 --- a/internal/frontend/qt/frontend_settings.go +++ b/internal/frontend/qt/frontend_settings.go @@ -159,10 +159,12 @@ func (f *FrontendQt) setKeychain() { availableKeychain = append(availableKeychain, chain) } f.qml.SetAvailableKeychain(availableKeychain) - f.qml.SetSelectedKeychain(f.bridge.GetKeychainApp()) + f.qml.SetCurrentKeychain(f.bridge.GetKeychainApp()) } -func (f *FrontendQt) selectKeychain(wantKeychain string) { +func (f *FrontendQt) changeKeychain(wantKeychain string) { + defer f.qml.ChangeKeychainFinished() + if f.bridge.GetKeychainApp() == wantKeychain { return } diff --git a/internal/frontend/qt/qml_backend.go b/internal/frontend/qt/qml_backend.go index 756f6c0d..b02f87c9 100644 --- a/internal/frontend/qt/qml_backend.go +++ b/internal/frontend/qt/qml_backend.go @@ -138,8 +138,9 @@ type QMLBackend struct { _ func() `signal:"bugReportSendError"` _ []string `property:"availableKeychain"` - _ string `property:"selectedKeychain"` - _ func(keychain string) `slot:"selectKeychain"` + _ string `property:"currentKeychain"` + _ func(keychain string) `slot:"changeKeychain"` + _ func() `signal:"changeKeychainFinished"` _ func() `signal:"notifyHasNoKeychain"` _ func(email string) `signal:noActiveKeyForRecipient` @@ -287,10 +288,10 @@ func (q *QMLBackend) setup(f *FrontendQt) { }) f.setKeychain() - q.ConnectSelectKeychain(func(k string) { + q.ConnectChangeKeychain(func(k string) { go func() { defer f.panicHandler.HandlePanic() - f.selectKeychain(k) + f.changeKeychain(k) }() }) }