466 lines
15 KiB
QML
466 lines
15 KiB
QML
// 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/>.
|
|
|
|
// Dialog with adding new user
|
|
|
|
import QtQuick 2.8
|
|
import ProtonUI 1.0
|
|
|
|
|
|
Dialog {
|
|
id: root
|
|
|
|
title : ""
|
|
|
|
signal createAccount()
|
|
|
|
property alias inputPassword : inputPassword
|
|
property alias input2FAuth : input2FAuth
|
|
property alias inputPasswMailbox : inputPasswMailbox
|
|
//
|
|
property alias username : inputUsername.text
|
|
property alias usernameElided : usernameMetrics.elidedText
|
|
|
|
isDialogBusy : currentIndex==waitingAuthIndex || currentIndex==addingAccIndex
|
|
|
|
property bool isFirstAccount: false
|
|
|
|
property color buttonOpaqueMain : "white"
|
|
|
|
|
|
property int origin: 0
|
|
property int nameAndPasswordIndex : 0
|
|
property int waitingAuthIndex : 2
|
|
property int twoFAIndex : 1
|
|
property int mailboxIndex : 3
|
|
property int addingAccIndex : 4
|
|
property int newAccountIndex : 5
|
|
|
|
|
|
signal cancel()
|
|
signal okay()
|
|
|
|
TextMetrics {
|
|
id: usernameMetrics
|
|
font: dialogWaitingAuthText.font
|
|
elideWidth : Style.dialog.widthInput
|
|
elide : Qt.ElideMiddle
|
|
text : root.username
|
|
}
|
|
|
|
Column { // 0
|
|
id: dialogNameAndPassword
|
|
property int heightInputs : inputUsername.height + buttonRow.height + middleSep.height + inputPassword.height + middleSepPassw.height
|
|
|
|
Rectangle {
|
|
id: topSep
|
|
color : "transparent"
|
|
width : Style.main.dummy
|
|
// Hacky hack: +10 is to make title of Dialog bigger so longer error can fit just fine.
|
|
height : root.height/2 + 10 - (dialogNameAndPassword.heightInputs)/2
|
|
}
|
|
|
|
InputField {
|
|
id: inputUsername
|
|
iconText : Style.fa.user_circle
|
|
label : qsTr("Username", "enter username to add account")
|
|
onAccepted : inputPassword.focusInput = true
|
|
}
|
|
|
|
Rectangle { id: middleSepPassw; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator}
|
|
|
|
InputField {
|
|
id: inputPassword
|
|
label : qsTr("Password", "password entry field")
|
|
iconText : Style.fa.lock
|
|
isPassword : true
|
|
onAccepted : root.okay()
|
|
}
|
|
|
|
Rectangle { id: middleSep; color : "transparent"; width : Style.main.dummy; height : 2*Style.dialog.heightSeparator }
|
|
|
|
Row {
|
|
id: buttonRow
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
spacing: Style.dialog.fontSize
|
|
ButtonRounded {
|
|
id:buttonCancel
|
|
fa_icon : Style.fa.times
|
|
text : qsTr("Cancel", "dismisses current action")
|
|
color_main : Style.dialog.text
|
|
onClicked : root.cancel()
|
|
}
|
|
ButtonRounded {
|
|
id: buttonNext
|
|
fa_icon : Style.fa.check
|
|
text : qsTr("Next", "navigate to next page in add account flow")
|
|
color_main : buttonOpaqueMain
|
|
color_minor : Style.dialog.textBlue
|
|
isOpaque : true
|
|
onClicked : root.okay()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
color : "transparent"
|
|
width : Style.main.dummy
|
|
height : root.height - (topSep.height + dialogNameAndPassword.heightInputs + Style.main.bottomMargin + signUpForAccount.height)
|
|
}
|
|
|
|
ClickIconText {
|
|
id: signUpForAccount
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
fontSize : Style.dialog.fontSize
|
|
iconSize : Style.dialog.fontSize
|
|
iconText : "+"
|
|
text : qsTr ("Sign Up for an Account", "takes user to web page where they can create a ProtonMail account")
|
|
textBold : true
|
|
textUnderline : true
|
|
textColor : Style.dialog.text
|
|
onClicked : root.createAccount()
|
|
}
|
|
}
|
|
|
|
Column { // 1
|
|
id: dialog2FA
|
|
property int heightInputs : buttonRowPassw.height + middleSep2FA.height + input2FAuth.height
|
|
|
|
Rectangle {
|
|
color : "transparent"
|
|
width : Style.main.dummy
|
|
height : (root.height - dialog2FA.heightInputs)/2
|
|
}
|
|
|
|
InputField {
|
|
id: input2FAuth
|
|
label : qsTr("Two Factor Code", "two factor code entry field")
|
|
iconText : Style.fa.lock
|
|
onAccepted : root.okay()
|
|
}
|
|
|
|
Rectangle { id: middleSep2FA; color : "transparent"; width : Style.main.dummy; height : 2*Style.dialog.heightSeparator }
|
|
|
|
Row {
|
|
id: buttonRowPassw
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
spacing: Style.dialog.fontSize
|
|
ButtonRounded {
|
|
id: buttonBack
|
|
fa_icon: Style.fa.times
|
|
text: qsTr("Back", "navigate back in add account flow")
|
|
color_main: Style.dialog.text
|
|
onClicked : root.cancel()
|
|
}
|
|
ButtonRounded {
|
|
id: buttonNextTwo
|
|
fa_icon: Style.fa.check
|
|
text: qsTr("Next", "navigate to next page in add account flow")
|
|
color_main: buttonOpaqueMain
|
|
color_minor: Style.dialog.textBlue
|
|
isOpaque: true
|
|
onClicked : root.okay()
|
|
}
|
|
}
|
|
}
|
|
|
|
Column { // 2
|
|
id: dialogWaitingAuth
|
|
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-dialogWaitingAuthText.height) /2 }
|
|
Text {
|
|
id: dialogWaitingAuthText
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
color: Style.dialog.text
|
|
font.pointSize: Style.dialog.fontSize * Style.pt
|
|
text : qsTr("Logging in") +"\n" + root.usernameElided
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
}
|
|
|
|
Column { // 3
|
|
id: dialogMailboxPassword
|
|
property int heightInputs : buttonRowMailbox.height + inputPasswMailbox.height + middleSepMailbox.height
|
|
|
|
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height - dialogMailboxPassword.heightInputs)/2}
|
|
|
|
InputField {
|
|
id: inputPasswMailbox
|
|
label : qsTr("Mailbox password for %1", "mailbox password entry field").arg(root.usernameElided)
|
|
iconText : Style.fa.lock
|
|
isPassword : true
|
|
onAccepted : root.okay()
|
|
}
|
|
|
|
Rectangle { id: middleSepMailbox; color : "transparent"; width : Style.main.dummy; height : 2*Style.dialog.heightSeparator }
|
|
|
|
Row {
|
|
id: buttonRowMailbox
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
spacing: Style.dialog.fontSize
|
|
ButtonRounded {
|
|
id: buttonBackBack
|
|
fa_icon: Style.fa.times
|
|
text: qsTr("Back", "navigate back in add account flow")
|
|
color_main: Style.dialog.text
|
|
onClicked : root.cancel()
|
|
}
|
|
ButtonRounded {
|
|
id: buttonLogin
|
|
fa_icon: Style.fa.check
|
|
text: qsTr("Next", "navigate to next page in add account flow")
|
|
color_main: buttonOpaqueMain
|
|
color_minor: Style.dialog.textBlue
|
|
isOpaque: true
|
|
onClicked : root.okay()
|
|
}
|
|
}
|
|
}
|
|
|
|
Column { // 4
|
|
id: dialogWaitingAccount
|
|
|
|
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height - dialogWaitingAccountText.height )/2 }
|
|
|
|
Text {
|
|
id: dialogWaitingAccountText
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
color: Style.dialog.text
|
|
font {
|
|
bold : true
|
|
pointSize: Style.dialog.fontSize * Style.pt
|
|
}
|
|
text : qsTr("Adding account, please wait ...", "displayed after user has logged in, before new account is displayed")
|
|
wrapMode: Text.Wrap
|
|
}
|
|
}
|
|
|
|
Column { // 5
|
|
id: dialogFirstUserAdded
|
|
|
|
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height - dialogWaitingAccountText.height - okButton.height*2 )/2 }
|
|
|
|
Text {
|
|
id: textFirstUser
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
color: Style.dialog.text
|
|
font {
|
|
bold : false
|
|
pointSize: Style.dialog.fontSize * Style.pt
|
|
}
|
|
width: 2*root.width/3
|
|
horizontalAlignment: Text.AlignHCenter
|
|
textFormat: Text.RichText
|
|
text: "<html><style>a { font-weight: bold; text-decoration: none; color: white;}</style>"+
|
|
qsTr("Now you need to configure your client(s) to use the Bridge. Instructions for configuring your client can be found at", "") +
|
|
"<br/><a href=\"https://protonmail.com/bridge/clients\">https://protonmail.com/bridge/clients</a>.<html>"
|
|
wrapMode: Text.Wrap
|
|
onLinkActivated: {
|
|
Qt.openUrlExternally(link)
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
cursorShape: parent.hoveredLink=="" ? Qt.PointingHandCursor : Qt.WaitCursor
|
|
acceptedButtons: Qt.NoButton
|
|
}
|
|
}
|
|
|
|
Rectangle { color : "transparent"; width : Style.main.dummy; height : okButton.height}
|
|
|
|
ButtonRounded{
|
|
id: okButton
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
color_main: buttonOpaqueMain
|
|
color_minor: Style.main.textBlue
|
|
isOpaque: true
|
|
text: qsTr("Okay", "confirms and dismisses a notification")
|
|
onClicked: root.hide()
|
|
}
|
|
}
|
|
|
|
function clear_user() {
|
|
inputUsername.text = ""
|
|
inputUsername.rightIcon = ""
|
|
}
|
|
|
|
function clear_passwd() {
|
|
inputPassword.text = ""
|
|
inputPassword.rightIcon = ""
|
|
inputPassword.hidePasswordText()
|
|
}
|
|
|
|
|
|
function clear_2fa() {
|
|
input2FAuth.text = ""
|
|
input2FAuth.rightIcon = ""
|
|
}
|
|
|
|
function clear_passwd_mailbox() {
|
|
inputPasswMailbox.text = ""
|
|
inputPasswMailbox.rightIcon = ""
|
|
inputPasswMailbox.hidePasswordText()
|
|
}
|
|
|
|
onCancel : {
|
|
root.warning.visible=false
|
|
if (currentIndex==0) {
|
|
root.hide()
|
|
} else {
|
|
clear_passwd()
|
|
clear_passwd_mailbox()
|
|
currentIndex=0
|
|
}
|
|
}
|
|
|
|
|
|
function check_inputs() {
|
|
var isOK = true
|
|
switch (currentIndex) {
|
|
case nameAndPasswordIndex :
|
|
isOK &= inputUsername.checkNonEmpty()
|
|
isOK &= inputPassword.checkNonEmpty()
|
|
break
|
|
case twoFAIndex :
|
|
isOK &= input2FAuth.checkNonEmpty()
|
|
break
|
|
case mailboxIndex :
|
|
isOK &= inputPasswMailbox.checkNonEmpty()
|
|
break
|
|
}
|
|
if (isOK) {
|
|
warning.visible = false
|
|
warning.text= ""
|
|
} else {
|
|
setWarning(qsTr("Field required", "a field that must be filled in to submit form"),0)
|
|
}
|
|
return isOK
|
|
}
|
|
|
|
function setWarning(msg, changeIndex) {
|
|
// show message
|
|
root.warning.text = msg
|
|
root.warning.visible = true
|
|
}
|
|
|
|
|
|
onOkay : {
|
|
var isOK = check_inputs()
|
|
if (isOK) {
|
|
root.origin = root.currentIndex
|
|
switch (root.currentIndex) {
|
|
case nameAndPasswordIndex:
|
|
case twoFAIndex:
|
|
root.currentIndex = waitingAuthIndex
|
|
break;
|
|
case mailboxIndex:
|
|
root.currentIndex = addingAccIndex
|
|
}
|
|
timer.start()
|
|
}
|
|
}
|
|
|
|
onShow: {
|
|
root.title = qsTr ("Log in to your ProtonMail account", "displayed on screen when user enters username to begin adding account")
|
|
root.warning.visible = false
|
|
inputUsername.forceFocus()
|
|
root.isFirstAccount = go.isFirstStart && accountsModel.count==0
|
|
}
|
|
|
|
function startAgain() {
|
|
clear_passwd()
|
|
clear_2fa()
|
|
clear_passwd_mailbox()
|
|
root.currentIndex = nameAndPasswordIndex
|
|
root.inputPassword.focusInput = true
|
|
}
|
|
|
|
function finishLogin(){
|
|
root.currentIndex = addingAccIndex
|
|
var auth = go.addAccount(inputPasswMailbox.text)
|
|
if (auth<0) {
|
|
startAgain()
|
|
return
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: timer
|
|
|
|
onTriggered : {
|
|
timer.repeat = false
|
|
switch (root.origin) {
|
|
case nameAndPasswordIndex:
|
|
var auth = go.login(inputUsername.text, inputPassword.text)
|
|
if (auth < 0) {
|
|
startAgain()
|
|
break
|
|
}
|
|
if (auth == 1) {
|
|
root.currentIndex = twoFAIndex
|
|
root.input2FAuth.focusInput = true
|
|
break
|
|
}
|
|
if (auth == 2) {
|
|
root.currentIndex = mailboxIndex
|
|
root.inputPasswMailbox.focusInput = true
|
|
break
|
|
}
|
|
root.inputPasswMailbox.text = inputPassword.text
|
|
root.finishLogin()
|
|
break;
|
|
case twoFAIndex:
|
|
var auth = go.auth2FA(input2FAuth.text)
|
|
if (auth < 0) {
|
|
startAgain()
|
|
break
|
|
}
|
|
if (auth == 1) {
|
|
root.currentIndex = mailboxIndex
|
|
root.inputPasswMailbox.focusInput = true
|
|
break
|
|
}
|
|
root.inputPasswMailbox.text = inputPassword.text
|
|
root.finishLogin()
|
|
break;
|
|
case mailboxIndex:
|
|
root.finishLogin()
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
onHide: {
|
|
// because hide slot is conneceted to processFinished it will update
|
|
// the list evertyime `go` obejcet is finished
|
|
clear_passwd()
|
|
clear_passwd_mailbox()
|
|
clear_2fa()
|
|
clear_user()
|
|
go.loadAccounts()
|
|
if (root.isFirstAccount && accountsModel.count==1) {
|
|
root.isFirstAccount=false
|
|
root.currentIndex=5
|
|
root.show()
|
|
root.title=qsTr("Success, Account Added!", "shown after successful account addition")
|
|
}
|
|
}
|
|
|
|
Keys.onPressed: {
|
|
if (event.key == Qt.Key_Enter) {
|
|
root.okay()
|
|
}
|
|
}
|
|
}
|