GODT-937: Add keychain switcher to frontend

GODT-1008: Fix transparent dialog under certain conditions
This commit is contained in:
Alexander Bilyak
2021-02-10 00:49:39 +01:00
committed by James Houlahan
parent 8b436186a4
commit 0fe69d9de1
11 changed files with 267 additions and 0 deletions

View File

@ -210,3 +210,13 @@ func (b *Bridge) SetUpdateChannel(channel updater.UpdateChannel) error {
return b.versioner.RemoveOtherVersions(version.Version) return b.versioner.RemoveOtherVersions(version.Version)
} }
// GetKeychainApp returns current keychain helper.
func (b *Bridge) GetKeychainApp() string {
return b.settings.Get(settings.PreferredKeychainKey)
}
// SetKeychainApp sets current keychain helper.
func (b *Bridge) SetKeychainApp(helper string) {
b.settings.Set(settings.PreferredKeychainKey, helper)
}

View File

@ -0,0 +1,194 @@
// Copyright (c) 2021 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 <https://www.gnu.org/licenses/>.
// Change default keychain dialog
import QtQuick 2.8
import BridgeUI 1.0
import ProtonUI 1.0
import QtQuick.Controls 2.2 as QC
import QtQuick.Layouts 1.0
Dialog {
id: root
title : "Change which keychain Bridge uses as default"
subtitle : "Select which keychain is used (Bridge will automatically restart)"
isDialogBusy: currentIndex==1
property var selectedKeychain
Connections {
target: go.selectedKeychain
onValueChanged: {
console.debug("go.selectedKeychain == ", go.selectedKeychain)
}
}
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
Item {
Layout.fillWidth: true
Layout.minimumHeight: root.titleHeight + Style.dialog.heightSeparator
Layout.maximumHeight: root.titleHeight + Style.dialog.heightSeparator
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
ColumnLayout {
anchors.centerIn: parent
Repeater {
id: keychainRadioButtons
model: go.availableKeychain
QC.RadioButton {
id: radioDelegate
text: modelData
checked: go.selectedKeychain === modelData
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: Style.main.spacing
indicator: Text {
text : radioDelegate.checked ? Style.fa.check_circle : Style.fa.circle_o
color : radioDelegate.checked ? Style.main.textBlue : Style.main.textInactive
font {
pointSize: Style.dialog.iconSize * Style.pt
family: Style.fontawesome.name
}
}
contentItem: Text {
text: radioDelegate.text
color: Style.main.text
font {
pointSize: Style.dialog.fontSize * Style.pt
bold: checked
}
horizontalAlignment : Text.AlignHCenter
verticalAlignment : Text.AlignVCenter
leftPadding: Style.dialog.iconSize
}
onCheckedChanged: {
if (checked) {
root.selectedKeychain = modelData
}
}
}
}
Item {
Layout.fillWidth: true
Layout.minimumHeight: Style.dialog.heightSeparator
Layout.maximumHeight: Style.dialog.heightSeparator
}
Row {
id: buttonRow
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
spacing: Style.dialog.spacing
ButtonRounded {
id:buttonNo
color_main: Style.dialog.text
fa_icon: Style.fa.times
text: qsTr("Cancel", "dismisses current action")
onClicked : root.hide()
}
ButtonRounded {
id: buttonYes
color_main: Style.dialog.text
color_minor: Style.main.textBlue
isOpaque: true
fa_icon: Style.fa.check
text: qsTr("Okay", "confirms and dismisses a notification")
onClicked : root.confirmed()
}
}
}
}
}
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
Item {
Layout.fillWidth: true
Layout.minimumHeight: root.titleHeight + Style.dialog.heightSeparator
Layout.maximumHeight: root.titleHeight + Style.dialog.heightSeparator
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Text {
id: answ
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width : parent.width/2
color: Style.dialog.text
font {
pointSize : Style.dialog.fontSize * Style.pt
bold : true
}
text : "Default keychain is now set to " + root.selectedKeychain +
"\n\n" +
qsTr("Settings will be applied after the next start.", "notification about setting being applied after next start") +
"\n\n" +
qsTr("Bridge will now restart.", "notification about restarting")
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
}
}
}
Shortcut {
sequence: StandardKey.Cancel
onActivated: root.hide()
}
Shortcut {
sequence: "Enter"
onActivated: root.confirmed()
}
function confirmed() {
if (selectedKeychain === go.selectedKeychain) {
root.hide()
return
}
incrementCurrentIndex()
timer.start()
}
timer.interval : 5000
Connections {
target: timer
onTriggered: {
// This action triggers restart on the backend side.
go.selectedKeychain = selectedKeychain
}
}
}

View File

@ -303,6 +303,10 @@ Window {
id: dialogChangePort id: dialogChangePort
} }
DialogKeychainChange {
id: dialogChangeKeychain
}
DialogConnectionTroubleshoot { DialogConnectionTroubleshoot {
id: dialogConnectionTroubleshoot id: dialogConnectionTroubleshoot
} }

View File

@ -239,6 +239,25 @@ Item {
dialogGlobal.show() dialogGlobal.show()
} }
} }
ButtonIconText {
id: changeKeychain
visible: advancedSettings.isAdvanced && (go.availableKeychain.length > 1)
text: qsTr("Change keychain", "button to open dialog with default keychain selection")
leftIcon.text : Style.fa.key
rightIcon {
text : qsTr("Change", "clickable link next to change keychain button in settings")
color: Style.main.text
font {
family : changeKeychain.font.family // use default font, not font-awesome
pointSize : Style.settings.fontSize * Style.pt
underline : true
}
}
onClicked: {
dialogChangeKeychain.show()
}
}
} }
} }
} }

View File

@ -2,6 +2,7 @@ module BridgeUI
AccountDelegate 1.0 AccountDelegate.qml AccountDelegate 1.0 AccountDelegate.qml
Credits 1.0 Credits.qml Credits 1.0 Credits.qml
DialogFirstStart 1.0 DialogFirstStart.qml DialogFirstStart 1.0 DialogFirstStart.qml
DialogKeychainChange 1.0 DialogKeychainChange.qml
DialogPortChange 1.0 DialogPortChange.qml DialogPortChange 1.0 DialogPortChange.qml
DialogYesNo 1.0 DialogYesNo.qml DialogYesNo 1.0 DialogYesNo.qml
DialogTLSCertInfo 1.0 DialogTLSCertInfo.qml DialogTLSCertInfo 1.0 DialogTLSCertInfo.qml

View File

@ -111,6 +111,11 @@ StackLayout {
Accessible.description: title Accessible.description: title
Accessible.focusable: true Accessible.focusable: true
onVisibleChanged: {
if (background.visible != visible) {
background.visible = visible
}
}
visible : false visible : false
anchors { anchors {

View File

@ -281,6 +281,9 @@ Window {
property bool hasNoKeychain : true property bool hasNoKeychain : true
property var availableKeychain: ["pass-app", "gnome-keyring"]
property var selectedKeychain: "gnome-keyring"
property string wrongCredentials property string wrongCredentials
property string wrongMailboxPassword property string wrongMailboxPassword
property string canNotReachAPI property string canNotReachAPI

View File

@ -45,6 +45,7 @@ import (
"github.com/ProtonMail/proton-bridge/internal/frontend/types" "github.com/ProtonMail/proton-bridge/internal/frontend/types"
"github.com/ProtonMail/proton-bridge/internal/locations" "github.com/ProtonMail/proton-bridge/internal/locations"
"github.com/ProtonMail/proton-bridge/internal/updater" "github.com/ProtonMail/proton-bridge/internal/updater"
"github.com/ProtonMail/proton-bridge/pkg/keychain"
"github.com/ProtonMail/proton-bridge/pkg/listener" "github.com/ProtonMail/proton-bridge/pkg/listener"
"github.com/ProtonMail/proton-bridge/pkg/pmapi" "github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/ProtonMail/proton-bridge/pkg/ports" "github.com/ProtonMail/proton-bridge/pkg/ports"
@ -372,6 +373,14 @@ func (s *FrontendQt) qtExecute(Procedure func(*FrontendQt) error) error {
s.Qml.SetIsEarlyAccess(false) s.Qml.SetIsEarlyAccess(false)
} }
availableKeychain := []string{}
for chain := range keychain.Helpers {
availableKeychain = append(availableKeychain, chain)
}
s.Qml.SetAvailableKeychain(availableKeychain)
s.Qml.SetSelectedKeychain(s.settings.Get(settings.PreferredKeychainKey))
// Set reporting of outgoing email without encryption. // Set reporting of outgoing email without encryption.
s.Qml.SetIsReportingOutgoingNoEnc(s.settings.GetBool(settings.ReportOutgoingNoEncKey)) s.Qml.SetIsReportingOutgoingNoEnc(s.settings.GetBool(settings.ReportOutgoingNoEncKey))
@ -711,3 +720,16 @@ func (s *FrontendQt) setGUIIsReady() {
s.initializing.Done() s.initializing.Done()
}) })
} }
func (s *FrontendQt) getKeychain() string {
return s.bridge.GetKeychainApp()
}
func (s *FrontendQt) setKeychain(keychain string) {
if keychain != s.bridge.GetKeychainApp() {
s.bridge.SetKeychainApp(keychain)
s.restarter.SetToRestart()
s.App.Quit()
}
}

View File

@ -66,6 +66,9 @@ type GoQMLInterface struct {
_ func() `slot:"startManualUpdate"` _ func() `slot:"startManualUpdate"`
_ func() `slot:"guiIsReady"` _ func() `slot:"guiIsReady"`
_ []string `property:"availableKeychain"`
_ string `property:"selectedKeychain"`
// Translations. // Translations.
_ string `property:"wrongCredentials"` _ string `property:"wrongCredentials"`
_ string `property:"wrongMailboxPassword"` _ string `property:"wrongMailboxPassword"`
@ -209,4 +212,7 @@ func (s *GoQMLInterface) SetFrontend(f *FrontendQt) {
s.ConnectToggleIsReportingOutgoingNoEnc(f.toggleIsReportingOutgoingNoEnc) s.ConnectToggleIsReportingOutgoingNoEnc(f.toggleIsReportingOutgoingNoEnc)
s.ConnectShouldSendAnswer(f.shouldSendAnswer) s.ConnectShouldSendAnswer(f.shouldSendAnswer)
s.ConnectSaveOutgoingNoEncPopupCoord(f.saveOutgoingNoEncPopupCoord) s.ConnectSaveOutgoingNoEncPopupCoord(f.saveOutgoingNoEncPopupCoord)
s.ConnectSetSelectedKeychain(f.setKeychain)
s.ConnectSelectedKeychain(f.getKeychain)
} }

View File

@ -61,6 +61,7 @@
<file alias="BubbleMenu.qml" >./qml/BridgeUI/BubbleMenu.qml</file> <file alias="BubbleMenu.qml" >./qml/BridgeUI/BubbleMenu.qml</file>
<file alias="Credits.qml" >./qml/BridgeUI/Credits.qml</file> <file alias="Credits.qml" >./qml/BridgeUI/Credits.qml</file>
<file alias="DialogFirstStart.qml" >./qml/BridgeUI/DialogFirstStart.qml</file> <file alias="DialogFirstStart.qml" >./qml/BridgeUI/DialogFirstStart.qml</file>
<file alias="DialogKeychainChange.qml" >./qml/BridgeUI/DialogKeychainChange.qml</file>
<file alias="DialogPortChange.qml" >./qml/BridgeUI/DialogPortChange.qml</file> <file alias="DialogPortChange.qml" >./qml/BridgeUI/DialogPortChange.qml</file>
<file alias="DialogYesNo.qml" >./qml/BridgeUI/DialogYesNo.qml</file> <file alias="DialogYesNo.qml" >./qml/BridgeUI/DialogYesNo.qml</file>
<file alias="DialogTLSCertInfo.qml" >./qml/BridgeUI/DialogTLSCertInfo.qml</file> <file alias="DialogTLSCertInfo.qml" >./qml/BridgeUI/DialogTLSCertInfo.qml</file>

View File

@ -82,6 +82,8 @@ type Bridger interface {
DisallowProxy() DisallowProxy()
GetUpdateChannel() updater.UpdateChannel GetUpdateChannel() updater.UpdateChannel
SetUpdateChannel(updater.UpdateChannel) error SetUpdateChannel(updater.UpdateChannel) error
GetKeychainApp() string
SetKeychainApp(keychain string)
} }
type bridgeWrap struct { type bridgeWrap struct {