mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-17 15:46:44 +00:00
We build too many walls and not enough bridges
This commit is contained in:
430
internal/frontend/qml/BridgeUI/AccountDelegate.qml
Normal file
430
internal/frontend/qml/BridgeUI/AccountDelegate.qml
Normal file
@ -0,0 +1,430 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
import BridgeUI 1.0
|
||||
|
||||
// NOTE: Keep the Column so the height and width is inherited from content
|
||||
Column {
|
||||
id: root
|
||||
state: status
|
||||
anchors.left: parent.left
|
||||
|
||||
property int row_width: 50 * Style.px
|
||||
property int row_height: Style.accounts.heightAccount
|
||||
property var listalias : aliases.split(";")
|
||||
property int iAccount: index
|
||||
|
||||
Accessible.role: go.goos=="windows" ? Accessible.Grouping : Accessible.Row
|
||||
Accessible.name: qsTr("Account %1, status %2", "Accessible text describing account row with arguments: account name and status (connected/disconnected), resp.").arg(account).arg(statusMark.text)
|
||||
Accessible.description: Accessible.name
|
||||
Accessible.ignored: !enabled || !visible
|
||||
|
||||
// Main row
|
||||
Rectangle {
|
||||
id: mainaccRow
|
||||
anchors.left: parent.left
|
||||
width : row_width
|
||||
height : row_height
|
||||
state: { return isExpanded ? "expanded" : "collapsed" }
|
||||
color: Style.main.background
|
||||
|
||||
property string actionName : (
|
||||
isExpanded ?
|
||||
qsTr("Collapse row for account %2", "Accessible text of button showing additional configuration of account") :
|
||||
qsTr("Expand row for account %2", "Accessible text of button hiding additional configuration of account")
|
||||
). arg(account)
|
||||
|
||||
|
||||
// override by other buttons
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
onClicked : {
|
||||
if (root.state=="connected") {
|
||||
mainaccRow.toggle_accountSettings()
|
||||
}
|
||||
}
|
||||
cursorShape : root.state == "connected" ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
if (mainaccRow.state=="collapsed") {
|
||||
mainaccRow.color = Qt.lighter(Style.main.background,1.1)
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
if (mainaccRow.state=="collapsed") {
|
||||
mainaccRow.color = Style.main.background
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// toggle down/up icon
|
||||
Text {
|
||||
id: toggleIcon
|
||||
anchors {
|
||||
left : parent.left
|
||||
verticalCenter : parent.verticalCenter
|
||||
leftMargin : Style.main.leftMargin
|
||||
}
|
||||
color: Style.main.text
|
||||
font {
|
||||
pointSize : Style.accounts.sizeChevron * Style.pt
|
||||
family : Style.fontawesome.name
|
||||
}
|
||||
text: Style.fa.chevron_down
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: mainaccRow.actionName
|
||||
Accessible.description: mainaccRow.actionName
|
||||
Accessible.onPressAction : mainaccRow.toggle_accountSettings()
|
||||
Accessible.ignored: root.state!="connected" || !root.enabled
|
||||
}
|
||||
}
|
||||
|
||||
// account name
|
||||
TextMetrics {
|
||||
id: accountMetrics
|
||||
font : accountName.font
|
||||
elide: Qt.ElideMiddle
|
||||
elideWidth: Style.accounts.elideWidth
|
||||
text: account
|
||||
}
|
||||
Text {
|
||||
id: accountName
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
left : toggleIcon.left
|
||||
leftMargin : Style.main.leftMargin
|
||||
}
|
||||
color: Style.main.text
|
||||
font {
|
||||
pointSize : (Style.main.fontSize+2*Style.px) * Style.pt
|
||||
}
|
||||
text: accountMetrics.elidedText
|
||||
}
|
||||
|
||||
// status
|
||||
ClickIconText {
|
||||
id: statusMark
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
left : parent.left
|
||||
leftMargin : Style.accounts.leftMargin2
|
||||
}
|
||||
text : qsTr("connected", "status of a listed logged-in account")
|
||||
iconText : Style.fa.circle_o
|
||||
textColor : Style.main.textGreen
|
||||
enabled : false
|
||||
Accessible.ignored: true
|
||||
}
|
||||
|
||||
// logout
|
||||
ClickIconText {
|
||||
id: logoutAccount
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
left : parent.left
|
||||
leftMargin : Style.accounts.leftMargin3
|
||||
}
|
||||
text : qsTr("Log out", "action to log out a connected account")
|
||||
iconText : Style.fa.power_off
|
||||
textBold : true
|
||||
textColor : Style.main.textBlue
|
||||
}
|
||||
|
||||
// remove
|
||||
ClickIconText {
|
||||
id: deleteAccount
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
right : parent.right
|
||||
rightMargin : Style.main.rightMargin
|
||||
}
|
||||
text : qsTr("Remove", "deletes an account from the account settings page")
|
||||
iconText : Style.fa.trash_o
|
||||
textColor : Style.main.text
|
||||
onClicked : {
|
||||
dialogGlobal.input=root.iAccount
|
||||
dialogGlobal.state="deleteUser"
|
||||
dialogGlobal.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// functions
|
||||
function toggle_accountSettings() {
|
||||
if (root.state=="connected") {
|
||||
if (mainaccRow.state=="collapsed" ) {
|
||||
mainaccRow.state="expanded"
|
||||
} else {
|
||||
mainaccRow.state="collapsed"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "collapsed"
|
||||
PropertyChanges { target : toggleIcon ; text : root.state=="connected" ? Style.fa.chevron_down : " " }
|
||||
PropertyChanges { target : accountName ; font.bold : false }
|
||||
PropertyChanges { target : mainaccRow ; color : Style.main.background }
|
||||
PropertyChanges { target : addressList ; visible : false }
|
||||
},
|
||||
State {
|
||||
name: "expanded"
|
||||
PropertyChanges { target : toggleIcon ; text : Style.fa.chevron_up }
|
||||
PropertyChanges { target : accountName ; font.bold : true }
|
||||
PropertyChanges { target : mainaccRow ; color : Style.accounts.backgroundExpanded }
|
||||
PropertyChanges { target : addressList ; visible : true }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// List of adresses
|
||||
Column {
|
||||
id: addressList
|
||||
anchors.left : parent.left
|
||||
width: row_width
|
||||
visible: false
|
||||
property alias model : repeaterAddresses.model
|
||||
|
||||
Rectangle {
|
||||
id: addressModeWrapper
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
}
|
||||
visible : mainaccRow.state=="expanded"
|
||||
height : 2*Style.accounts.heightAddrRow/3
|
||||
color : Style.accounts.backgroundExpanded
|
||||
|
||||
ClickIconText {
|
||||
id: addressModeSwitch
|
||||
anchors {
|
||||
top : addressModeWrapper.top
|
||||
right : addressModeWrapper.right
|
||||
rightMargin : Style.main.rightMargin
|
||||
}
|
||||
textColor : Style.main.textBlue
|
||||
iconText : Style.fa.exchange
|
||||
iconOnRight : false
|
||||
text : isCombinedAddressMode ?
|
||||
qsTr("Switch to split addresses mode", "Text of button switching to mode with one configuration per each address.") :
|
||||
qsTr("Switch to combined addresses mode", "Text of button switching to mode with one configuration for all addresses.")
|
||||
|
||||
onClicked: {
|
||||
dialogGlobal.input=root.iAccount
|
||||
dialogGlobal.state="addressmode"
|
||||
dialogGlobal.show()
|
||||
}
|
||||
}
|
||||
|
||||
ClickIconText {
|
||||
id: combinedAddressConfig
|
||||
anchors {
|
||||
top : addressModeWrapper.top
|
||||
left : addressModeWrapper.left
|
||||
leftMargin : Style.accounts.leftMarginAddr+Style.main.leftMargin
|
||||
}
|
||||
visible : isCombinedAddressMode
|
||||
text : qsTr("Mailbox configuration", "Displays IMAP/SMTP settings information for a given account")
|
||||
iconText : Style.fa.gear
|
||||
textColor : Style.main.textBlue
|
||||
onClicked : {
|
||||
infoWin.showInfo(root.iAccount,0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: repeaterAddresses
|
||||
model: ["one", "two"]
|
||||
|
||||
Rectangle {
|
||||
id: addressRow
|
||||
visible: !isCombinedAddressMode
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
}
|
||||
height: Style.accounts.heightAddrRow
|
||||
color: Style.accounts.backgroundExpanded
|
||||
|
||||
// icon level down
|
||||
Text {
|
||||
id: levelDown
|
||||
anchors {
|
||||
left : parent.left
|
||||
leftMargin : Style.accounts.leftMarginAddr
|
||||
verticalCenter : wrapAddr.verticalCenter
|
||||
}
|
||||
text : Style.fa.level_up
|
||||
font.family : Style.fontawesome.name
|
||||
color : Style.main.textDisabled
|
||||
rotation : 90
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: wrapAddr
|
||||
anchors {
|
||||
top : parent.top
|
||||
left : levelDown.right
|
||||
right : parent.right
|
||||
leftMargin : Style.main.leftMargin
|
||||
rightMargin : Style.main.rightMargin
|
||||
}
|
||||
height: Style.accounts.heightAddr
|
||||
border {
|
||||
width : Style.main.border
|
||||
color : Style.main.line
|
||||
}
|
||||
color: Style.accounts.backgroundAddrRow
|
||||
|
||||
TextMetrics {
|
||||
id: addressMetrics
|
||||
font: address.font
|
||||
elideWidth: 2*wrapAddr.width/3
|
||||
elide: Qt.ElideMiddle
|
||||
text: modelData
|
||||
}
|
||||
|
||||
Text {
|
||||
id: address
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
left: parent.left
|
||||
leftMargin: Style.main.leftMargin
|
||||
}
|
||||
font.pointSize : Style.main.fontSize * Style.pt
|
||||
color: Style.main.text
|
||||
text: addressMetrics.elidedText
|
||||
}
|
||||
|
||||
ClickIconText {
|
||||
id: addressConfig
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
right: parent.right
|
||||
rightMargin: Style.main.rightMargin
|
||||
}
|
||||
text : qsTr("Address configuration", "Display the IMAP/SMTP configuration for address")
|
||||
iconText : Style.fa.gear
|
||||
textColor : Style.main.textBlue
|
||||
onClicked : infoWin.showInfo(root.iAccount,index)
|
||||
|
||||
Accessible.description: qsTr("Address configuration for %1", "Accessible text of button displaying the IMAP/SMTP configuration for address %1").arg(modelData)
|
||||
Accessible.ignored: !enabled
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: clickSettings
|
||||
anchors.fill: wrapAddr
|
||||
onClicked : addressConfig.clicked()
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
onPressed: {
|
||||
wrapAddr.color = Qt.rgba(1,1,1,0.20)
|
||||
}
|
||||
onEntered: {
|
||||
wrapAddr.color = Qt.rgba(1,1,1,0.15)
|
||||
}
|
||||
onExited: {
|
||||
wrapAddr.color = Style.accounts.backgroundAddrRow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: line
|
||||
color: Style.accounts.line
|
||||
height: Style.accounts.heightLine
|
||||
width: root.row_width
|
||||
}
|
||||
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "connected"
|
||||
PropertyChanges {
|
||||
target : addressList
|
||||
model : listalias
|
||||
}
|
||||
PropertyChanges {
|
||||
target : toggleIcon
|
||||
color : Style.main.text
|
||||
}
|
||||
PropertyChanges {
|
||||
target : accountName
|
||||
color : Style.main.text
|
||||
}
|
||||
PropertyChanges {
|
||||
target : statusMark
|
||||
textColor : Style.main.textGreen
|
||||
text : qsTr("connected", "status of a listed logged-in account")
|
||||
iconText : Style.fa.circle
|
||||
}
|
||||
PropertyChanges {
|
||||
target : logoutAccount
|
||||
text : qsTr("Log out", "action to log out a connected account")
|
||||
onClicked : {
|
||||
mainaccRow.state="collapsed"
|
||||
dialogGlobal.input = root.iAccount
|
||||
dialogGlobal.state = "logout"
|
||||
dialogGlobal.show()
|
||||
dialogGlobal.confirmed()
|
||||
}
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "disconnected"
|
||||
PropertyChanges {
|
||||
target : addressList
|
||||
model : 0
|
||||
}
|
||||
PropertyChanges {
|
||||
target : toggleIcon
|
||||
color : Style.main.textDisabled
|
||||
}
|
||||
PropertyChanges {
|
||||
target : accountName
|
||||
color : Style.main.textDisabled
|
||||
}
|
||||
PropertyChanges {
|
||||
target : statusMark
|
||||
textColor : Style.main.textDisabled
|
||||
text : qsTr("disconnected", "status of a listed logged-out account")
|
||||
iconText : Style.fa.circle_o
|
||||
}
|
||||
PropertyChanges {
|
||||
target : logoutAccount
|
||||
text : qsTr("Log in", "action to log in a disconnected account")
|
||||
onClicked : {
|
||||
dialogAddUser.username = root.listalias[0]
|
||||
dialogAddUser.show()
|
||||
dialogAddUser.inputPassword.focusInput = true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
72
internal/frontend/qml/BridgeUI/BubbleMenu.qml
Normal file
72
internal/frontend/qml/BridgeUI/BubbleMenu.qml
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2020 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 main menu
|
||||
|
||||
import QtQuick 2.8
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: "#aaff5577"
|
||||
anchors {
|
||||
left : tabbar.left
|
||||
right : tabbar.right
|
||||
top : tabbar.bottom
|
||||
bottom : parent.bottom
|
||||
}
|
||||
visible: false
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: toggle()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color : Style.menu.background
|
||||
radius : Style.menu.radius
|
||||
width : Style.menu.width
|
||||
height : Style.menu.height
|
||||
anchors {
|
||||
top : parent.top
|
||||
right : parent.right
|
||||
topMargin : Style.menu.topMargin
|
||||
rightMargin : Style.menu.rightMargin
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("About")
|
||||
color: Style.menu.text
|
||||
}
|
||||
}
|
||||
|
||||
function toggle(){
|
||||
if (root.visible == false) {
|
||||
root.visible = true
|
||||
} else {
|
||||
root.visible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
49
internal/frontend/qml/BridgeUI/Credits.qml
Normal file
49
internal/frontend/qml/BridgeUI/Credits.qml
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import QtQuick 2.8
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
Item {
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: Style.main.width
|
||||
height: 3*Style.main.height/4
|
||||
color: "transparent"
|
||||
//color: "red"
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
clip : true
|
||||
model : go.credits.split(";")
|
||||
|
||||
delegate: AccessibleText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: modelData
|
||||
color: Style.main.text
|
||||
font.pointSize : Style.main.fontSize * Style.pt
|
||||
}
|
||||
|
||||
footer: ButtonRounded {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: qsTr("Close", "close window")
|
||||
onClicked: dialogCredits.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
124
internal/frontend/qml/BridgeUI/DialogFirstStart.qml
Normal file
124
internal/frontend/qml/BridgeUI/DialogFirstStart.qml
Normal file
@ -0,0 +1,124 @@
|
||||
// Copyright (c) 2020 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 Yes/No buttons
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
|
||||
title : ""
|
||||
isDialogBusy: false
|
||||
property string firstParagraph : qsTr("The Bridge is an application that runs on your computer in the background and seamlessly encrypts and decrypts your mail as it enters and leaves your computer.", "instructions that appear on welcome screen at first start")
|
||||
property string secondParagraph : qsTr("To add your ProtonMail account to the Bridge and <strong>generate your Bridge password</strong>, please see <a href=\"https://protonmail.com/bridge/install\">the installation guide</a> for detailed setup instructions.", "confirms and dismisses a notification (URL that leads to installation guide should stay intact)")
|
||||
|
||||
Column {
|
||||
id: dialogMessage
|
||||
property int heightInputs : welcome.height + middleSep.height + instructions.height + buttSep.height + buttonOkay.height + imageSep.height + logo.height
|
||||
|
||||
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-dialogMessage.heightInputs)/2 }
|
||||
|
||||
Text {
|
||||
id:welcome
|
||||
color: Style.main.text
|
||||
font.bold: true
|
||||
font.pointSize: 1.5*Style.main.fontSize*Style.pt
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Welcome to the", "welcome screen that appears on first start")
|
||||
}
|
||||
|
||||
Rectangle {id: imageSep; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator }
|
||||
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Style.dialog.spacing
|
||||
Image {
|
||||
id: logo
|
||||
anchors.bottom : pmbridge.baseline
|
||||
height : 2*Style.main.fontSize
|
||||
fillMode : Image.PreserveAspectFit
|
||||
mipmap : true
|
||||
source : "../ProtonUI/images/pm_logo.png"
|
||||
}
|
||||
AccessibleText {
|
||||
id:pmbridge
|
||||
color: Style.main.text
|
||||
font.bold: true
|
||||
font.pointSize: 2.2*Style.main.fontSize*Style.pt
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("ProtonMail Bridge", "app title")
|
||||
|
||||
Accessible.name: this.clearText(pmbridge.text)
|
||||
Accessible.description: this.clearText(welcome.text+ " " + pmbridge.text + ". " + root.firstParagraph + ". " + root.secondParagraph)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Rectangle { id:middleSep; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator }
|
||||
|
||||
|
||||
Text {
|
||||
id:instructions
|
||||
color: Style.main.text
|
||||
font.pointSize: Style.main.fontSize*Style.pt
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
width: root.width/1.5
|
||||
wrapMode: Text.Wrap
|
||||
textFormat: Text.RichText
|
||||
text: "<html><style>a { color: "+Style.main.textBlue+"; text-decoration: none;}</style><body>"+
|
||||
root.firstParagraph +
|
||||
"<br/><br/>"+
|
||||
root.secondParagraph +
|
||||
"</body></html>"
|
||||
onLinkActivated: {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { id:buttSep; color : "transparent"; width : Style.main.dummy; height : 2*Style.dialog.heightSeparator }
|
||||
|
||||
|
||||
ButtonRounded {
|
||||
id:buttonOkay
|
||||
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.hide()
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
timer.interval : 3000
|
||||
|
||||
Connections {
|
||||
target: timer
|
||||
onTriggered: {
|
||||
}
|
||||
}
|
||||
|
||||
onShow : {
|
||||
pmbridge.Accessible.selected = true
|
||||
}
|
||||
}
|
||||
233
internal/frontend/qml/BridgeUI/DialogPortChange.qml
Normal file
233
internal/frontend/qml/BridgeUI/DialogPortChange.qml
Normal file
@ -0,0 +1,233 @@
|
||||
// Copyright (c) 2020 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 Yes/No buttons
|
||||
|
||||
import QtQuick 2.8
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
import QtQuick.Controls 2.2 as QC
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
|
||||
title : "Set IMAP & SMTP settings"
|
||||
subtitle : "Changes require reconfiguration of Mail client. (Bridge will automatically restart)"
|
||||
isDialogBusy: currentIndex==1
|
||||
|
||||
Column {
|
||||
id: dialogMessage
|
||||
property int heightInputs : imapPort.height + middleSep.height + smtpPort.height + buttonSep.height + buttonRow.height + secSMTPSep.height + securitySMTP.height
|
||||
|
||||
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-dialogMessage.heightInputs)/1.6 }
|
||||
|
||||
InputField {
|
||||
id: imapPort
|
||||
iconText : Style.fa.hashtag
|
||||
label : qsTr("IMAP port", "entry field to choose port used for the IMAP server")
|
||||
text : "undef"
|
||||
}
|
||||
|
||||
Rectangle { id:middleSep; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator }
|
||||
|
||||
InputField {
|
||||
id: smtpPort
|
||||
iconText : Style.fa.hashtag
|
||||
label : qsTr("SMTP port", "entry field to choose port used for the SMTP server")
|
||||
text : "undef"
|
||||
}
|
||||
|
||||
Rectangle { id:secSMTPSep; color : Style.transparent; width : Style.main.dummy; height : Style.dialog.heightSeparator }
|
||||
|
||||
// SSL button group
|
||||
Rectangle {
|
||||
anchors.horizontalCenter : parent.horizontalCenter
|
||||
width : Style.dialog.widthInput
|
||||
height : securitySMTPLabel.height + securitySMTP.height
|
||||
color : "transparent"
|
||||
|
||||
AccessibleText {
|
||||
id: securitySMTPLabel
|
||||
anchors.left : parent.left
|
||||
text:qsTr("SMTP connection mode")
|
||||
color: Style.dialog.text
|
||||
font {
|
||||
pointSize : Style.dialog.fontSize * Style.pt
|
||||
bold : true
|
||||
}
|
||||
}
|
||||
|
||||
QC.ButtonGroup {
|
||||
buttons: securitySMTP.children
|
||||
}
|
||||
Row {
|
||||
id: securitySMTP
|
||||
spacing: Style.dialog.spacing
|
||||
anchors.top: securitySMTPLabel.bottom
|
||||
anchors.topMargin: Style.dialog.fontSize
|
||||
|
||||
CheckBoxLabel {
|
||||
id: securitySMTPSSL
|
||||
text: qsTr("SSL")
|
||||
}
|
||||
|
||||
CheckBoxLabel {
|
||||
checked: true
|
||||
id: securitySMTPSTARTTLS
|
||||
text: qsTr("STARTTLS")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { id:buttonSep; color : "transparent"; width : Style.main.dummy; height : 2*Style.dialog.heightSeparator }
|
||||
|
||||
Row {
|
||||
id: buttonRow
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-answ.height)/2 }
|
||||
Text {
|
||||
id: answ
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width : parent.width/2
|
||||
color: Style.dialog.text
|
||||
font {
|
||||
pointSize : Style.dialog.fontSize * Style.pt
|
||||
bold : true
|
||||
}
|
||||
text : "IMAP: " + imapPort.text + "\nSMTP: " + smtpPort.text + "\nSMTP Connection Mode: " + getSelectedSSLMode() + "\n\n" +
|
||||
qsTr("Settings will be applied after the next start. You will need to reconfigure your email client(s).", "after user changes their ports they will see this notification to reconfigure their setup") +
|
||||
"\n\n" +
|
||||
qsTr("Bridge will now restart.", "after user changes their ports this appears to notify the user of restart")
|
||||
wrapMode: Text.Wrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
function areInputsOK() {
|
||||
var isOK = true
|
||||
var imapUnchanged = false
|
||||
var secSMTPUnchanged = (securitySMTPSTARTTLS.checked == go.isSMTPSTARTTLS())
|
||||
root.warning.text = ""
|
||||
|
||||
if (imapPort.text!=go.getIMAPPort()) {
|
||||
if (go.isPortOpen(imapPort.text)!=0) {
|
||||
imapPort.rightIcon = Style.fa.exclamation_triangle
|
||||
root.warning.text = qsTr("Port number is not available.", "if the user changes one of their ports to a port that is occupied by another application")
|
||||
isOK=false
|
||||
} else {
|
||||
imapPort.rightIcon = Style.fa.check_circle
|
||||
}
|
||||
} else {
|
||||
imapPort.rightIcon = ""
|
||||
imapUnchanged = true
|
||||
}
|
||||
|
||||
if (smtpPort.text!=go.getSMTPPort()) {
|
||||
if (go.isPortOpen(smtpPort.text)!=0) {
|
||||
smtpPort.rightIcon = Style.fa.exclamation_triangle
|
||||
root.warning.text = qsTr("Port number is not available.", "if the user changes one of their ports to a port that is occupied by another application")
|
||||
isOK=false
|
||||
} else {
|
||||
smtpPort.rightIcon = Style.fa.check_circle
|
||||
}
|
||||
} else {
|
||||
smtpPort.rightIcon = ""
|
||||
if (imapUnchanged && secSMTPUnchanged) {
|
||||
root.warning.text = qsTr("Please change at least one port number or SMTP security.", "if the user tries to change IMAP/SMTP ports to the same ports as before")
|
||||
isOK=false
|
||||
}
|
||||
}
|
||||
|
||||
if (imapPort.text == smtpPort.text) {
|
||||
smtpPort.rightIcon = Style.fa.exclamation_triangle
|
||||
root.warning.text = qsTr("Port numbers must be different.", "if the user sets both the IMAP and SMTP ports to the same number")
|
||||
isOK=false
|
||||
}
|
||||
|
||||
root.warning.visible = !isOK
|
||||
return isOK
|
||||
}
|
||||
|
||||
function confirmed() {
|
||||
if (areInputsOK()) {
|
||||
incrementCurrentIndex()
|
||||
timer.start()
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectedSSLMode() {
|
||||
if (securitySMTPSTARTTLS.checked == true) {
|
||||
return "STARTTLS"
|
||||
} else {
|
||||
return "SSL"
|
||||
}
|
||||
}
|
||||
|
||||
onShow : {
|
||||
imapPort.text = go.getIMAPPort()
|
||||
smtpPort.text = go.getSMTPPort()
|
||||
if (go.isSMTPSTARTTLS()) {
|
||||
securitySMTPSTARTTLS.checked = true
|
||||
} else {
|
||||
securitySMTPSSL.checked = true
|
||||
}
|
||||
areInputsOK()
|
||||
root.warning.visible = false
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: StandardKey.Cancel
|
||||
onActivated: root.hide()
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: "Enter"
|
||||
onActivated: root.confirmed()
|
||||
}
|
||||
|
||||
timer.interval : 3000
|
||||
|
||||
Connections {
|
||||
target: timer
|
||||
onTriggered: {
|
||||
go.setPortsAndSecurity(imapPort.text, smtpPort.text, securitySMTPSTARTTLS.checked)
|
||||
go.isRestarting = true
|
||||
Qt.quit()
|
||||
}
|
||||
}
|
||||
}
|
||||
77
internal/frontend/qml/BridgeUI/DialogTLSCertInfo.qml
Normal file
77
internal/frontend/qml/BridgeUI/DialogTLSCertInfo.qml
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import QtQuick 2.8
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
title: qsTr("Connection security error", "Title of modal explainning TLS issue")
|
||||
|
||||
property string par1Title : qsTr("Description:", "Title of paragraph describing the issue")
|
||||
property string par1Text : qsTr (
|
||||
"ProtonMail Bridge was not able to establish a secure connection to Proton servers due to a TLS certificate error. "+
|
||||
"This means your connection may potentially be insecure and susceptible to monitoring by third parties.",
|
||||
"A paragraph describing the issue"
|
||||
)
|
||||
|
||||
property string par2Title : qsTr("Recommendation:", "Title of paragraph describing recommended steps")
|
||||
property string par2Text : qsTr (
|
||||
"If you are on a corporate or public network, the network administrator may be monitoring or intercepting all traffic.",
|
||||
"A paragraph describing network issue"
|
||||
)
|
||||
property string par2ul1 : qsTr(
|
||||
"If you trust your network operator, you can continue to use ProtonMail as usual.",
|
||||
"A list item describing recomendation for trusted network"
|
||||
)
|
||||
|
||||
property string par2ul2 : qsTr(
|
||||
"If you don't trust your network operator, reconnect to ProtonMail over a VPN (such as ProtonVPN) "+
|
||||
"which encrypts your Internet connection, or use a different network to access ProtonMail.",
|
||||
"A list item describing recomendation for untrusted network"
|
||||
)
|
||||
property string par3Text : qsTr("Learn more on our knowledge base article","A paragraph describing where to find more information")
|
||||
property string kbArticleText : qsTr("What is TLS certificate error.", "Link text for knowledge base article")
|
||||
property string kbArticleLink : "https://protonmail.com/support/knowledge-base/"
|
||||
|
||||
|
||||
Item {
|
||||
AccessibleText {
|
||||
anchors.centerIn: parent
|
||||
color: Style.old.pm_white
|
||||
linkColor: color
|
||||
width: parent.width - 50 * Style.px
|
||||
wrapMode: Text.WordWrap
|
||||
font.pointSize: Style.main.fontSize*Style.pt
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
text: "<h3>"+par1Title+"</h3>"+
|
||||
par1Text+"<br>\n"+
|
||||
"<h3>"+par2Title+"</h3>"+
|
||||
par2Text+
|
||||
"<ul>"+
|
||||
"<li>"+par2ul1+"</li>"+
|
||||
"<li>"+par2ul2+"</li>"+
|
||||
"</ul>"+"<br>\n"+
|
||||
""
|
||||
//par3Text+
|
||||
//" <a href='"+kbArticleLink+"'>"+kbArticleText+"</a>\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
382
internal/frontend/qml/BridgeUI/DialogYesNo.qml
Normal file
382
internal/frontend/qml/BridgeUI/DialogYesNo.qml
Normal file
@ -0,0 +1,382 @@
|
||||
// Copyright (c) 2020 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 Yes/No buttons
|
||||
|
||||
import QtQuick 2.8
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
|
||||
title : ""
|
||||
|
||||
property string input
|
||||
|
||||
property alias question : msg.text
|
||||
property alias note : noteText.text
|
||||
property alias answer : answ.text
|
||||
property alias buttonYes : buttonYes
|
||||
property alias buttonNo : buttonNo
|
||||
|
||||
isDialogBusy: currentIndex==1
|
||||
|
||||
signal confirmed()
|
||||
|
||||
Column {
|
||||
id: dialogMessage
|
||||
property int heightInputs : msg.height+
|
||||
middleSep.height+
|
||||
buttonRow.height +
|
||||
(checkboxSep.visible ? checkboxSep.height : 0 ) +
|
||||
(noteSep.visible ? noteSep.height : 0 ) +
|
||||
(checkBoxWrapper.visible ? checkBoxWrapper.height : 0 ) +
|
||||
(root.note!="" ? noteText.height : 0 )
|
||||
|
||||
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-dialogMessage.heightInputs)/2 }
|
||||
|
||||
AccessibleText {
|
||||
id:noteText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: Style.dialog.text
|
||||
font {
|
||||
pointSize: Style.dialog.fontSize * Style.pt
|
||||
bold: false
|
||||
}
|
||||
width: 2*root.width/3
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
Rectangle { id: noteSep; visible: note!=""; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator}
|
||||
|
||||
AccessibleText {
|
||||
id: msg
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: Style.dialog.text
|
||||
font {
|
||||
pointSize: Style.dialog.fontSize * Style.pt
|
||||
bold: true
|
||||
}
|
||||
width: 2*parent.width/3
|
||||
text : ""
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
Rectangle { id: checkboxSep; visible: checkBoxWrapper.visible; color : "transparent"; width : Style.main.dummy; height : Style.dialog.heightSeparator}
|
||||
Row {
|
||||
id: checkBoxWrapper
|
||||
property bool isChecked : false
|
||||
visible: root.state=="deleteUser"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Style.dialog.spacing
|
||||
|
||||
function toggle() {
|
||||
checkBoxWrapper.isChecked = !checkBoxWrapper.isChecked
|
||||
}
|
||||
|
||||
Text {
|
||||
id: checkbox
|
||||
font {
|
||||
pointSize : Style.dialog.iconSize * Style.pt
|
||||
family : Style.fontawesome.name
|
||||
}
|
||||
anchors.verticalCenter : parent.verticalCenter
|
||||
text: checkBoxWrapper.isChecked ? Style.fa.check_square_o : Style.fa.square_o
|
||||
color: checkBoxWrapper.isChecked ? Style.main.textBlue : Style.main.text
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: checkBoxWrapper.toggle()
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
}
|
||||
Text {
|
||||
id: checkBoxNote
|
||||
anchors.verticalCenter : parent.verticalCenter
|
||||
text: qsTr("Additionally delete all stored preferences and data", "when removing an account, this extra preference additionally deletes all cached data")
|
||||
color: Style.main.text
|
||||
font.pointSize: Style.dialog.fontSize * Style.pt
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: checkBoxWrapper.toggle()
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
Accessible.role: Accessible.CheckBox
|
||||
Accessible.checked: checkBoxWrapper.isChecked
|
||||
Accessible.name: checkBoxNote.text
|
||||
Accessible.description: checkBoxNote.text
|
||||
Accessible.ignored: checkBoxNote.text == ""
|
||||
Accessible.onToggleAction: checkBoxWrapper.toggle()
|
||||
Accessible.onPressAction: checkBoxWrapper.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { id: middleSep; color : "transparent"; width : Style.main.dummy; height : 2*Style.dialog.heightSeparator }
|
||||
|
||||
Row {
|
||||
id: buttonRow
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Style.dialog.spacing
|
||||
ButtonRounded {
|
||||
id:buttonNo
|
||||
color_main: Style.dialog.text
|
||||
fa_icon: Style.fa.times
|
||||
text: qsTr("No")
|
||||
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("Yes")
|
||||
onClicked : {
|
||||
currentIndex=1
|
||||
root.confirmed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Column {
|
||||
Rectangle { color : "transparent"; width : Style.main.dummy; height : (root.height-answ.height)/2 }
|
||||
AccessibleText {
|
||||
id: answ
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: Style.old.pm_white
|
||||
font {
|
||||
pointSize : Style.dialog.fontSize * Style.pt
|
||||
bold : true
|
||||
}
|
||||
width: 3*parent.width/4
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text : qsTr("Waiting...", "in general this displays between screens when processing data takes a long time")
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
states : [
|
||||
State {
|
||||
name: "quit"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
currentIndex : 0
|
||||
title : qsTr("Close Bridge", "quits the application")
|
||||
question : qsTr("Are you sure you want to close the Bridge?", "asked when user tries to quit the application")
|
||||
note : ""
|
||||
answer : qsTr("Closing Bridge...", "displayed when user is quitting application")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "logout"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
currentIndex : 1
|
||||
title : qsTr("Logout", "title of page that displays during account logout")
|
||||
question : ""
|
||||
note : ""
|
||||
answer : qsTr("Logging out...", "displays during account logout")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "deleteUser"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
currentIndex : 0
|
||||
title : qsTr("Delete account", "title of page that displays during account deletion")
|
||||
question : qsTr("Are you sure you want to remove this account?", "displays during account deletion")
|
||||
note : ""
|
||||
answer : qsTr("Deleting ...", "displays during account deletion")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "clearChain"
|
||||
PropertyChanges {
|
||||
target : root
|
||||
currentIndex : 0
|
||||
title : qsTr("Clear keychain", "title of page that displays during keychain clearing")
|
||||
question : qsTr("Are you sure you want to clear your keychain?", "displays during keychain clearing")
|
||||
note : qsTr("This will remove all accounts that you have added to the Bridge and disconnect you from your email client(s).", "displays during keychain clearing")
|
||||
answer : qsTr("Clearing the keychain ...", "displays during keychain clearing")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "clearCache"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
currentIndex : 0
|
||||
title : qsTr("Clear cache", "title of page that displays during cache clearing")
|
||||
question : qsTr("Are you sure you want to clear your local cache?", "displays during cache clearing")
|
||||
note : qsTr("This will delete all of your stored preferences as well as cached email data for all accounts, temporarily slowing down the email download process significantly.", "displays during cache clearing")
|
||||
answer : qsTr("Clearing the cache ...", "displays during cache clearing")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "checkUpdates"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
currentIndex : 1
|
||||
title : ""
|
||||
question : ""
|
||||
note : ""
|
||||
answer : qsTr("Checking for updates ...", "displays if user clicks the Check for Updates button in the Help tab")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "addressmode"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
currentIndex : 0
|
||||
title : ""
|
||||
question : qsTr("Do you want to continue?", "asked when the user changes between split and combined address mode")
|
||||
note : qsTr("Changing between split and combined address mode will require you to delete your account(s) from your email client and begin the setup process from scratch.", "displayed when the user changes between split and combined address mode")
|
||||
answer : qsTr("Configuring address mode...", "displayed when the user changes between split and combined address mode")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "toggleAutoStart"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
currentIndex : 1
|
||||
question : ""
|
||||
note : ""
|
||||
title : ""
|
||||
answer : {
|
||||
var msgTurnOn = qsTr("Turning on automatic start of Bridge...", "when the automatic start feature is selected")
|
||||
var msgTurnOff = qsTr("Turning off automatic start of Bridge...", "when the automatic start feature is deselected")
|
||||
return go.isAutoStart==false ? msgTurnOff : msgTurnOn
|
||||
}
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "toggleAllowProxy"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
currentIndex : 0
|
||||
question : {
|
||||
var questionTurnOn = qsTr("Do you want to allow alternative routing?")
|
||||
var questionTurnOff = qsTr("Do you want to disallow alternative routing?")
|
||||
return go.isProxyAllowed==false ? questionTurnOn : questionTurnOff
|
||||
}
|
||||
note : qsTr("In case Proton sites are blocked, this setting allows Bridge to try alternative network routing to reach Proton, which can be useful for bypassing firewalls or network issues. We recommend keeping this setting on for greater reliability.")
|
||||
title : {
|
||||
var titleTurnOn = qsTr("Allow alternative routing")
|
||||
var titleTurnOff = qsTr("Disallow alternative routing")
|
||||
return go.isProxyAllowed==false ? titleTurnOn : titleTurnOff
|
||||
}
|
||||
answer : {
|
||||
var msgTurnOn = qsTr("Allowing Bridge to use alternative routing to connect to Proton...", "when the allow proxy feature is selected")
|
||||
var msgTurnOff = qsTr("Disallowing Bridge to use alternative routing to connect to Proton...", "when the allow proxy feature is deselected")
|
||||
return go.isProxyAllowed==false ? msgTurnOn : msgTurnOff
|
||||
}
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "noKeychain"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
currentIndex : 0
|
||||
note : qsTr(
|
||||
"%1 is not able to detected a supported password manager (pass, gnome-keyring). Please install and setup supported password manager and restart the application.",
|
||||
"Error message when no keychain is detected"
|
||||
).arg(go.programTitle)
|
||||
question : qsTr("Do you want to close application now?", "when no password manager found." )
|
||||
title : "No system password manager detected"
|
||||
answer : qsTr("Closing Bridge...", "displayed when user is quitting application")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "undef";
|
||||
PropertyChanges {
|
||||
target: root
|
||||
currentIndex : 1
|
||||
question : ""
|
||||
note : ""
|
||||
title : ""
|
||||
answer : ""
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
Shortcut {
|
||||
sequence: StandardKey.Cancel
|
||||
onActivated: root.hide()
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: "Enter"
|
||||
onActivated: root.confirmed()
|
||||
}
|
||||
|
||||
onHide: {
|
||||
checkBoxWrapper.isChecked = false
|
||||
state = "undef"
|
||||
}
|
||||
|
||||
onShow: {
|
||||
// hide all other dialogs
|
||||
winMain.dialogAddUser .visible = false
|
||||
winMain.dialogChangePort .visible = false
|
||||
winMain.dialogCredits .visible = false
|
||||
winMain.dialogVersionInfo .visible = false
|
||||
// dialogFirstStart should reappear again after closing global
|
||||
root.visible = true
|
||||
}
|
||||
|
||||
|
||||
|
||||
onConfirmed : {
|
||||
if (state == "quit" || state == "instance exists" ) {
|
||||
timer.interval = 1000
|
||||
} else {
|
||||
timer.interval = 300
|
||||
}
|
||||
answ.forceActiveFocus()
|
||||
timer.start()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: timer
|
||||
onTriggered: {
|
||||
if ( state == "addressmode" ) { go.switchAddressMode (input) }
|
||||
if ( state == "clearChain" ) { go.clearKeychain () }
|
||||
if ( state == "clearCache" ) { go.clearCache () }
|
||||
if ( state == "deleteUser" ) { go.deleteAccount (input, checkBoxWrapper.isChecked) }
|
||||
if ( state == "logout" ) { go.logoutAccount (input) }
|
||||
if ( state == "toggleAutoStart" ) { go.toggleAutoStart () }
|
||||
if ( state == "toggleAllowProxy" ) { go.toggleAllowProxy () }
|
||||
if ( state == "quit" ) { Qt.quit () }
|
||||
if ( state == "instance exists" ) { Qt.quit () }
|
||||
if ( state == "noKeychain" ) { Qt.quit () }
|
||||
if ( state == "checkUpdates" ) { go.runCheckVersion (true) }
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (event.key == Qt.Key_Enter) {
|
||||
root.confirmed()
|
||||
}
|
||||
}
|
||||
}
|
||||
134
internal/frontend/qml/BridgeUI/HelpView.qml
Normal file
134
internal/frontend/qml/BridgeUI/HelpView.qml
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// List the settings
|
||||
|
||||
import QtQuick 2.8
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// must have wrapper
|
||||
Rectangle {
|
||||
id: wrapper
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
color: Style.main.background
|
||||
|
||||
// content
|
||||
Column {
|
||||
anchors.horizontalCenter : parent.horizontalCenter
|
||||
|
||||
ButtonIconText {
|
||||
id: logs
|
||||
anchors.left: parent.left
|
||||
text: qsTr("Logs", "title of button that takes user to logs directory")
|
||||
leftIcon.text : Style.fa.align_justify
|
||||
rightIcon.text : Style.fa.chevron_circle_right
|
||||
rightIcon.font.pointSize : Style.settings.toggleSize * Style.pt
|
||||
onClicked: go.openLogs()
|
||||
}
|
||||
|
||||
ButtonIconText {
|
||||
id: bugreport
|
||||
anchors.left: parent.left
|
||||
text: qsTr("Report Bug", "title of button that takes user to bug report form")
|
||||
leftIcon.text : Style.fa.bug
|
||||
rightIcon.text : Style.fa.chevron_circle_right
|
||||
rightIcon.font.pointSize : Style.settings.toggleSize * Style.pt
|
||||
onClicked: bugreportWin.show()
|
||||
}
|
||||
|
||||
ButtonIconText {
|
||||
id: manual
|
||||
anchors.left: parent.left
|
||||
text: qsTr("Setup Guide", "title of button that opens setup and installation guide")
|
||||
leftIcon.text : Style.fa.book
|
||||
rightIcon.text : Style.fa.chevron_circle_right
|
||||
rightIcon.font.pointSize : Style.settings.toggleSize * Style.pt
|
||||
onClicked: go.openManual()
|
||||
}
|
||||
|
||||
ButtonIconText {
|
||||
id: updates
|
||||
anchors.left: parent.left
|
||||
text: qsTr("Check for Updates", "title of button to check for any app updates")
|
||||
leftIcon.text : Style.fa.refresh
|
||||
rightIcon.text : Style.fa.chevron_circle_right
|
||||
rightIcon.font.pointSize : Style.settings.toggleSize * Style.pt
|
||||
onClicked: {
|
||||
dialogGlobal.state="checkUpdates"
|
||||
dialogGlobal.show()
|
||||
dialogGlobal.confirmed()
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom version notes
|
||||
Rectangle {
|
||||
anchors.horizontalCenter : parent.horizontalCenter
|
||||
height: viewAccount.separatorNoAccount - 3.2*manual.height
|
||||
width: wrapper.width
|
||||
color : "transparent"
|
||||
AccessibleText {
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
color: Style.main.textDisabled
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
font.pointSize : Style.main.fontSize * Style.pt
|
||||
text:
|
||||
"ProtonMail Bridge "+go.getBackendVersion()+"\n"+
|
||||
"© 2020 Proton Technologies AG"
|
||||
}
|
||||
}
|
||||
Row {
|
||||
anchors.left : parent.left
|
||||
|
||||
Rectangle { height: Style.dialog.spacing; width: (wrapper.width- credits.width - release.width - sepaCreditsRelease.width)/2; color: "transparent"}
|
||||
|
||||
ClickIconText {
|
||||
id:credits
|
||||
iconText : ""
|
||||
text : qsTr("Credits", "link to click on to view list of credited libraries")
|
||||
textColor : Style.main.textDisabled
|
||||
fontSize : Style.main.fontSize
|
||||
textUnderline : true
|
||||
onClicked : winMain.dialogCredits.show()
|
||||
}
|
||||
|
||||
Rectangle {id: sepaCreditsRelease ; height: Style.dialog.spacing; width: Style.main.dummy; color: "transparent"}
|
||||
|
||||
ClickIconText {
|
||||
id:release
|
||||
iconText : ""
|
||||
text : qsTr("Release notes", "link to click on to view release notes for this version of the app")
|
||||
textColor : Style.main.textDisabled
|
||||
fontSize : Style.main.fontSize
|
||||
textUnderline : true
|
||||
onClicked : {
|
||||
go.getLocalVersionInfo()
|
||||
winMain.dialogVersionInfo.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
144
internal/frontend/qml/BridgeUI/InfoWindow.qml
Normal file
144
internal/frontend/qml/BridgeUI/InfoWindow.qml
Normal file
@ -0,0 +1,144 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Window for imap and smtp settings
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Window 2.2
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
|
||||
Window {
|
||||
id:root
|
||||
width : Style.info.width
|
||||
height : Style.info.height
|
||||
minimumWidth : Style.info.width
|
||||
minimumHeight : Style.info.height
|
||||
maximumWidth : Style.info.width
|
||||
maximumHeight : Style.info.height
|
||||
color: "transparent"
|
||||
flags : Qt.Window | Qt.Dialog | Qt.FramelessWindowHint
|
||||
title : address
|
||||
|
||||
Accessible.role: Accessible.Window
|
||||
Accessible.name: qsTr("Configuration information for %1").arg(address)
|
||||
Accessible.description: Accessible.name
|
||||
|
||||
property QtObject accData : QtObject { // avoid null-pointer error
|
||||
property string account : "undef"
|
||||
property string aliases : "undef"
|
||||
property string hostname : "undef"
|
||||
property string password : "undef"
|
||||
property int portIMAP : 0
|
||||
property int portSMTP : 0
|
||||
}
|
||||
property string address : "undef"
|
||||
property int indexAccount : 0
|
||||
property int indexAddress : 0
|
||||
|
||||
WindowTitleBar {
|
||||
id: titleBar
|
||||
window: root
|
||||
}
|
||||
|
||||
Rectangle { // background
|
||||
color: Style.main.background
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
top : titleBar.bottom
|
||||
bottom : parent.bottom
|
||||
}
|
||||
border {
|
||||
width: Style.main.border
|
||||
color: Style.tabbar.background
|
||||
}
|
||||
}
|
||||
|
||||
// info content
|
||||
Column {
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: titleBar.bottom
|
||||
leftMargin: Style.main.leftMargin
|
||||
topMargin: Style.info.topMargin
|
||||
}
|
||||
width : root.width - Style.main.leftMargin - Style.main.rightMargin
|
||||
|
||||
TextLabel { text: qsTr("IMAP SETTINGS", "title of the portion of the configuration screen that contains IMAP settings"); state: "heading" }
|
||||
Rectangle { width: parent.width; height: Style.info.topMargin; color: "#00000000"}
|
||||
Grid {
|
||||
columns: 2
|
||||
rowSpacing: Style.main.fontSize
|
||||
TextLabel { text: qsTr("Hostname", "in configuration screen, displays the server hostname (127.0.0.1)") + ":"} TextValue { text: root.accData.hostname }
|
||||
TextLabel { text: qsTr("Port", "in configuration screen, displays the server port (ex. 1025)") + ":"} TextValue { text: root.accData.portIMAP }
|
||||
TextLabel { text: qsTr("Username", "in configuration screen, displays the username to use with the desktop client") + ":"} TextValue { text: root.address }
|
||||
TextLabel { text: qsTr("Password", "in configuration screen, displays the Bridge password to use with the desktop client") + ":"} TextValue { text: root.accData.password }
|
||||
TextLabel { text: qsTr("Security", "in configuration screen, displays the IMAP security settings") + ":"} TextValue { text: "STARTTLS" }
|
||||
}
|
||||
Rectangle { width: Style.main.dummy; height: Style.main.fontSize; color: "#00000000"}
|
||||
Rectangle { width: Style.main.dummy; height: Style.info.topMargin; color: "#00000000"}
|
||||
|
||||
TextLabel { text: qsTr("SMTP SETTINGS", "title of the portion of the configuration screen that contains SMTP settings"); state: "heading" }
|
||||
Rectangle { width: Style.main.dummy; height: Style.info.topMargin; color: "#00000000"}
|
||||
Grid {
|
||||
columns: 2
|
||||
rowSpacing: Style.main.fontSize
|
||||
TextLabel { text: qsTr("Hostname", "in configuration screen, displays the server hostname (127.0.0.1)") + ":"} TextValue { text: root.accData.hostname }
|
||||
TextLabel { text: qsTr("Port", "in configuration screen, displays the server port (ex. 1025)") + ":"} TextValue { text: root.accData.portSMTP }
|
||||
TextLabel { text: qsTr("Username", "in configuration screen, displays the username to use with the desktop client") + ":"} TextValue { text: root.address }
|
||||
TextLabel { text: qsTr("Password", "in configuration screen, displays the Bridge password to use with the desktop client") + ":"} TextValue { text: root.accData.password }
|
||||
TextLabel { text: qsTr("Security", "in configuration screen, displays the SMTP security settings") + ":"} TextValue { text: go.isSMTPSTARTTLS() ? "STARTTLS" : "SSL" }
|
||||
}
|
||||
Rectangle { width: Style.main.dummy; height: Style.main.fontSize; color: "#00000000"}
|
||||
Rectangle { width: Style.main.dummy; height: Style.info.topMargin; color: "#00000000"}
|
||||
}
|
||||
|
||||
// apple mail button
|
||||
ButtonRounded{
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
bottom: parent.bottom
|
||||
bottomMargin: Style.info.topMargin
|
||||
}
|
||||
color_main : Style.main.textBlue
|
||||
isOpaque: false
|
||||
text: qsTr("Configure Apple Mail", "button on configuration screen to automatically configure Apple Mail")
|
||||
height: Style.main.fontSize*2
|
||||
width: 2*parent.width/3
|
||||
onClicked: {
|
||||
go.configureAppleMail(root.indexAccount, root.indexAddress)
|
||||
}
|
||||
visible: go.goos == "darwin"
|
||||
}
|
||||
|
||||
|
||||
function showInfo(iAccount, iAddress) {
|
||||
root.indexAccount = iAccount
|
||||
root.indexAddress = iAddress
|
||||
root.accData = accountsModel.get(iAccount)
|
||||
root.address = accData.aliases.split(";")[iAddress]
|
||||
root.show()
|
||||
root.raise()
|
||||
root.requestActivate()
|
||||
}
|
||||
|
||||
function hide() {
|
||||
root.visible = false
|
||||
}
|
||||
}
|
||||
455
internal/frontend/qml/BridgeUI/MainWindow.qml
Normal file
455
internal/frontend/qml/BridgeUI/MainWindow.qml
Normal file
@ -0,0 +1,455 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// This is main window
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Layouts 1.3
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
|
||||
// Main Window
|
||||
Window {
|
||||
id: root
|
||||
property alias tabbar : tabbar
|
||||
property alias viewContent : viewContent
|
||||
property alias viewAccount : viewAccount
|
||||
property alias dialogAddUser : dialogAddUser
|
||||
property alias dialogChangePort : dialogChangePort
|
||||
property alias dialogCredits : dialogCredits
|
||||
property alias dialogTlsCert : dialogTlsCert
|
||||
property alias dialogUpdate : dialogUpdate
|
||||
property alias dialogFirstStart : dialogFirstStart
|
||||
property alias dialogGlobal : dialogGlobal
|
||||
property alias dialogVersionInfo : dialogVersionInfo
|
||||
property alias dialogConnectionTroubleshoot : dialogConnectionTroubleshoot
|
||||
property alias bubbleNote : bubbleNote
|
||||
property alias addAccountTip : addAccountTip
|
||||
property alias updateState : infoBar.state
|
||||
property alias tlsBarState : tlsBar.state
|
||||
property int heightContent : height-titleBar.height
|
||||
|
||||
// main window appeareance
|
||||
width : Style.main.width
|
||||
height : Style.main.height
|
||||
flags : Qt.Window | Qt.FramelessWindowHint
|
||||
color: go.goos=="windows" ? "black" : "transparent"
|
||||
title: go.programTitle
|
||||
minimumWidth: Style.main.width
|
||||
minimumHeight: Style.main.height
|
||||
maximumWidth: Style.main.width
|
||||
|
||||
property bool isOutdateVersion : root.updateState == "forceUpdate"
|
||||
|
||||
property bool activeContent :
|
||||
!dialogAddUser .visible &&
|
||||
!dialogChangePort .visible &&
|
||||
!dialogCredits .visible &&
|
||||
!dialogTlsCert .visible &&
|
||||
!dialogUpdate .visible &&
|
||||
!dialogFirstStart .visible &&
|
||||
!dialogGlobal .visible &&
|
||||
!dialogVersionInfo .visible &&
|
||||
!bubbleNote .visible
|
||||
|
||||
Accessible.role: Accessible.Grouping
|
||||
Accessible.description: qsTr("Window %1").arg(title)
|
||||
Accessible.name: Accessible.description
|
||||
|
||||
|
||||
Component.onCompleted : {
|
||||
gui.winMain = root
|
||||
console.log("GraphicsInfo of", titleBar,
|
||||
"api" , titleBar.GraphicsInfo.api ,
|
||||
"majorVersion" , titleBar.GraphicsInfo.majorVersion ,
|
||||
"minorVersion" , titleBar.GraphicsInfo.minorVersion ,
|
||||
"profile" , titleBar.GraphicsInfo.profile ,
|
||||
"renderableType" , titleBar.GraphicsInfo.renderableType ,
|
||||
"shaderCompilationType" , titleBar.GraphicsInfo.shaderCompilationType ,
|
||||
"shaderSourceType" , titleBar.GraphicsInfo.shaderSourceType ,
|
||||
"shaderType" , titleBar.GraphicsInfo.shaderType)
|
||||
|
||||
tabbar.focusButton()
|
||||
}
|
||||
|
||||
WindowTitleBar {
|
||||
id: titleBar
|
||||
window: root
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
top : titleBar.bottom
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
bottom : parent.bottom
|
||||
}
|
||||
color: Style.title.background
|
||||
}
|
||||
|
||||
TLSCertPinIssueBar {
|
||||
id: tlsBar
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
top : titleBar.bottom
|
||||
leftMargin: Style.main.border
|
||||
rightMargin: Style.main.border
|
||||
}
|
||||
enabled : root.activeContent
|
||||
}
|
||||
|
||||
InformationBar {
|
||||
id: infoBar
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
top : tlsBar.bottom
|
||||
leftMargin: Style.main.border
|
||||
rightMargin: Style.main.border
|
||||
}
|
||||
enabled : root.activeContent
|
||||
}
|
||||
|
||||
|
||||
TabLabels {
|
||||
id: tabbar
|
||||
currentIndex : 0
|
||||
enabled: root.activeContent
|
||||
anchors {
|
||||
top : infoBar.bottom
|
||||
right : parent.right
|
||||
left : parent.left
|
||||
leftMargin: Style.main.border
|
||||
rightMargin: Style.main.border
|
||||
}
|
||||
model: [
|
||||
{ "title" : qsTr("Accounts" , "title of tab that shows account list" ), "iconText": Style.fa.user_circle_o },
|
||||
{ "title" : qsTr("Settings" , "title of tab that allows user to change settings" ), "iconText": Style.fa.cog },
|
||||
{ "title" : qsTr("Help" , "title of tab that shows the help menu" ), "iconText": Style.fa.life_ring }
|
||||
]
|
||||
}
|
||||
|
||||
// Content of tabs
|
||||
StackLayout {
|
||||
id: viewContent
|
||||
enabled: root.activeContent
|
||||
// dimensions
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
top : tabbar.bottom
|
||||
bottom : parent.bottom
|
||||
leftMargin: Style.main.border
|
||||
rightMargin: Style.main.border
|
||||
bottomMargin: Style.main.border
|
||||
}
|
||||
// attributes
|
||||
currentIndex : { return root.tabbar.currentIndex}
|
||||
clip : true
|
||||
// content
|
||||
AccountView {
|
||||
id: viewAccount
|
||||
onAddAccount: dialogAddUser.show()
|
||||
model: accountsModel
|
||||
delegate: AccountDelegate {
|
||||
row_width: viewContent.width
|
||||
}
|
||||
}
|
||||
|
||||
SettingsView { id: viewSettings; }
|
||||
HelpView { id: viewHelp; }
|
||||
}
|
||||
|
||||
|
||||
// Floating things
|
||||
|
||||
// Triangle
|
||||
Rectangle {
|
||||
id: tabtriangle
|
||||
visible: false
|
||||
property int margin : Style.main.leftMargin+ Style.tabbar.widthButton/2
|
||||
anchors {
|
||||
top : tabbar.bottom
|
||||
left : tabbar.left
|
||||
leftMargin : tabtriangle.margin - tabtriangle.width/2 + tabbar.currentIndex * tabbar.spacing
|
||||
}
|
||||
width: 2*Style.tabbar.heightTriangle
|
||||
height: Style.tabbar.heightTriangle
|
||||
color: "transparent"
|
||||
Canvas {
|
||||
anchors.fill: parent
|
||||
onPaint: {
|
||||
var ctx = getContext("2d")
|
||||
ctx.fillStyle = Style.tabbar.background
|
||||
ctx.moveTo(0 , 0)
|
||||
ctx.lineTo(width/2, height)
|
||||
ctx.lineTo(width , 0)
|
||||
ctx.closePath()
|
||||
ctx.fill()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bubble prevent action
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: titleBar.bottom
|
||||
bottom: parent.bottom
|
||||
}
|
||||
visible: bubbleNote.visible
|
||||
color: "#aa222222"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
}
|
||||
BubbleNote {
|
||||
id : bubbleNote
|
||||
visible : false
|
||||
Component.onCompleted : {
|
||||
bubbleNote.place(0)
|
||||
}
|
||||
}
|
||||
|
||||
BubbleNote {
|
||||
id:addAccountTip
|
||||
anchors.topMargin: viewAccount.separatorNoAccount - 2*Style.main.fontSize
|
||||
text : qsTr("Click here to start", "on first launch, this is displayed above the Add Account button to tell the user what to do first")
|
||||
state: (go.isFirstStart && viewAccount.numAccounts==0 && root.viewContent.currentIndex==0) ? "Visible" : "Invisible"
|
||||
bubbleColor: Style.main.textBlue
|
||||
|
||||
Component.onCompleted : {
|
||||
addAccountTip.place(-1)
|
||||
}
|
||||
enabled: false
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "Visible"
|
||||
// hack: opacity 100% makes buttons dialog windows quit wrong color
|
||||
PropertyChanges{target: addAccountTip; opacity: 0.999; visible: true}
|
||||
},
|
||||
State {
|
||||
name: "Invisible"
|
||||
PropertyChanges{target: addAccountTip; opacity: 0.0; visible: false}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "Visible"
|
||||
to: "Invisible"
|
||||
|
||||
SequentialAnimation{
|
||||
NumberAnimation {
|
||||
target: addAccountTip
|
||||
property: "opacity"
|
||||
duration: 0
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
NumberAnimation {
|
||||
target: addAccountTip
|
||||
property: "visible"
|
||||
duration: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "Invisible"
|
||||
to: "Visible"
|
||||
SequentialAnimation{
|
||||
NumberAnimation {
|
||||
target: addAccountTip
|
||||
property: "visible"
|
||||
duration: 300
|
||||
}
|
||||
NumberAnimation {
|
||||
target: addAccountTip
|
||||
property: "opacity"
|
||||
duration: 500
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// Dialogs
|
||||
DialogFirstStart {
|
||||
id: dialogFirstStart
|
||||
visible: go.isFirstStart && gui.isFirstWindow && !dialogGlobal.visible
|
||||
}
|
||||
|
||||
// Dialogs
|
||||
DialogPortChange {
|
||||
id: dialogChangePort
|
||||
}
|
||||
|
||||
DialogConnectionTroubleshoot {
|
||||
id: dialogConnectionTroubleshoot
|
||||
}
|
||||
|
||||
DialogAddUser {
|
||||
id: dialogAddUser
|
||||
onCreateAccount: Qt.openUrlExternally("https://protonmail.com/signup")
|
||||
}
|
||||
|
||||
DialogUpdate {
|
||||
id: dialogUpdate
|
||||
|
||||
property string manualLinks : {
|
||||
var out = ""
|
||||
var links = go.downloadLink.split("\n")
|
||||
var l;
|
||||
for (l in links) {
|
||||
out += '<a href="%1">%1</a><br>'.arg(links[l])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
title: root.isOutdateVersion ?
|
||||
qsTr("%1 is outdated", "title of outdate dialog").arg(go.programTitle):
|
||||
qsTr("%1 update to %2", "title of update dialog").arg(go.programTitle).arg(go.newversion)
|
||||
introductionText: {
|
||||
if (root.isOutdateVersion) {
|
||||
if (go.goos=="linux") {
|
||||
return qsTr('You are using an outdated version of our software.<br>
|
||||
Please download and install the latest version to continue using %1.<br><br>
|
||||
%2',
|
||||
"Message for force-update in Linux").arg(go.programTitle).arg(dialogUpdate.manualLinks)
|
||||
} else {
|
||||
return qsTr('You are using an outdated version of our software.<br>
|
||||
Please download and install the latest version to continue using %1.<br><br>
|
||||
You can continue with the update or download and install the new version manually from<br><br>
|
||||
<a href="%2">%2</a>',
|
||||
"Message for force-update in Win/Mac").arg(go.programTitle).arg(go.landingPage)
|
||||
}
|
||||
} else {
|
||||
if (go.goos=="linux") {
|
||||
return qsTr('A new version of Bridge is available.<br>
|
||||
Check <a href="%1">release notes</a> to learn what is new in %2.<br>
|
||||
Use your package manager to update or download and install the new version manually from<br><br>
|
||||
%3',
|
||||
"Message for update in Linux").arg("releaseNotes").arg(go.newversion).arg(dialogUpdate.manualLinks)
|
||||
} else {
|
||||
return qsTr('A new version of Bridge is available.<br>
|
||||
Check <a href="%1">release notes</a> to learn what is new in %2.<br>
|
||||
You can continue with the update or download and install new version manually from<br><br>
|
||||
<a href="%3">%3</a>',
|
||||
"Message for update in Win/Mac").arg("releaseNotes").arg(go.newversion).arg(go.landingPage)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Dialog {
|
||||
id: dialogCredits
|
||||
title: qsTr("Credits", "link to click on to view list of credited libraries")
|
||||
Credits { }
|
||||
}
|
||||
|
||||
DialogTLSCertInfo {
|
||||
id: dialogTlsCert
|
||||
}
|
||||
|
||||
Dialog {
|
||||
id: dialogVersionInfo
|
||||
property bool checkVersionOnClose : false
|
||||
title: qsTr("Information about", "title of release notes page") + " v" + go.newversion
|
||||
VersionInfo { }
|
||||
onShow : {
|
||||
// Hide information bar with old version
|
||||
if (infoBar.state=="oldVersion") {
|
||||
infoBar.state="upToDate"
|
||||
dialogVersionInfo.checkVersionOnClose = true
|
||||
}
|
||||
}
|
||||
onHide : {
|
||||
// Reload current version based on online status
|
||||
if (dialogVersionInfo.checkVersionOnClose) go.runCheckVersion(false)
|
||||
dialogVersionInfo.checkVersionOnClose = false
|
||||
}
|
||||
}
|
||||
|
||||
DialogYesNo {
|
||||
id: dialogGlobal
|
||||
question : ""
|
||||
answer : ""
|
||||
z: 100
|
||||
}
|
||||
|
||||
|
||||
// resize
|
||||
MouseArea {
|
||||
property int diff: 0
|
||||
anchors {
|
||||
bottom : parent.bottom
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
}
|
||||
cursorShape: Qt.SizeVerCursor
|
||||
height: Style.main.fontSize
|
||||
onPressed: {
|
||||
var globPos = mapToGlobal(mouse.x, mouse.y)
|
||||
diff = root.height
|
||||
diff -= globPos.y
|
||||
}
|
||||
onMouseYChanged : {
|
||||
var globPos = mapToGlobal(mouse.x, mouse.y)
|
||||
root.height = Math.max(root.minimumHeight, globPos.y + diff)
|
||||
}
|
||||
}
|
||||
|
||||
function showAndRise(){
|
||||
go.loadAccounts()
|
||||
root.show()
|
||||
root.raise()
|
||||
if (!root.active) {
|
||||
root.requestActivate()
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle window
|
||||
function toggle() {
|
||||
go.loadAccounts()
|
||||
if (root.visible) {
|
||||
if (!root.active) {
|
||||
root.raise()
|
||||
root.requestActivate()
|
||||
} else {
|
||||
root.hide()
|
||||
}
|
||||
} else {
|
||||
root.show()
|
||||
root.raise()
|
||||
}
|
||||
}
|
||||
|
||||
onClosing: {
|
||||
close.accepted = false
|
||||
// NOTE: In order to make an initial accounts load
|
||||
root.hide()
|
||||
gui.closeMainWindow()
|
||||
}
|
||||
}
|
||||
16
internal/frontend/qml/BridgeUI/ManualWindow.qml
Normal file
16
internal/frontend/qml/BridgeUI/ManualWindow.qml
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
148
internal/frontend/qml/BridgeUI/OutgoingNoEncPopup.qml
Normal file
148
internal/frontend/qml/BridgeUI/OutgoingNoEncPopup.qml
Normal file
@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Popup
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Window 2.2
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
Window {
|
||||
id:root
|
||||
width : Style.info.width
|
||||
height : Style.info.width/1.5
|
||||
minimumWidth : Style.info.width
|
||||
minimumHeight : Style.info.width/1.5
|
||||
maximumWidth : Style.info.width
|
||||
maximumHeight : Style.info.width/1.5
|
||||
color : Style.main.background
|
||||
flags : Qt.Window | Qt.Popup | Qt.FramelessWindowHint
|
||||
visible : false
|
||||
title : ""
|
||||
x: 10
|
||||
y: 10
|
||||
property string messageID: ""
|
||||
|
||||
// Drag and move
|
||||
MouseArea {
|
||||
property point diff: "0,0"
|
||||
property QtObject window: root
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
diff = Qt.point(window.x, window.y)
|
||||
var mousePos = mapToGlobal(mouse.x, mouse.y)
|
||||
diff.x -= mousePos.x
|
||||
diff.y -= mousePos.y
|
||||
}
|
||||
|
||||
onPositionChanged: {
|
||||
var currPos = mapToGlobal(mouse.x, mouse.y)
|
||||
window.x = currPos.x + diff.x
|
||||
window.y = currPos.y + diff.y
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
topPadding: Style.main.fontSize
|
||||
spacing: (root.height - (description.height + cancel.height + countDown.height + Style.main.fontSize))/3
|
||||
width: root.width
|
||||
|
||||
Text {
|
||||
id: description
|
||||
color : Style.main.text
|
||||
font.pointSize : Style.main.fontSize*Style.pt/1.2
|
||||
anchors.horizontalCenter : parent.horizontalCenter
|
||||
horizontalAlignment : Text.AlignHCenter
|
||||
width : root.width - 2*Style.main.leftMargin
|
||||
wrapMode : Text.Wrap
|
||||
textFormat : Text.RichText
|
||||
|
||||
text: qsTr("The message with subject %1 has one or more recipients with no encryption settings. If you do not want to send this email click the cancel button.").arg("<h3>"+root.title+"</h3>")
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing : Style.dialog.spacing
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
ButtonRounded {
|
||||
id: cancel
|
||||
onClicked : root.hide(true)
|
||||
height: Style.main.fontSize*2
|
||||
//width: Style.dialog.widthButton*1.3
|
||||
fa_icon: Style.fa.send
|
||||
text: qsTr("Send now", "Confirmation of sending unencrypted email.")
|
||||
}
|
||||
|
||||
ButtonRounded {
|
||||
id: sendAnyway
|
||||
onClicked : root.hide(false)
|
||||
height: Style.main.fontSize*2
|
||||
//width: Style.dialog.widthButton*1.3
|
||||
fa_icon: Style.fa.times
|
||||
text: qsTr("Cancel", "Cancel the sending of current email")
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: countDown
|
||||
color: Style.main.text
|
||||
font.pointSize : Style.main.fontSize*Style.pt/1.2
|
||||
anchors.horizontalCenter : parent.horizontalCenter
|
||||
horizontalAlignment : Text.AlignHCenter
|
||||
width : root.width - 2*Style.main.leftMargin
|
||||
wrapMode : Text.Wrap
|
||||
textFormat : Text.RichText
|
||||
|
||||
text: qsTr("This popup will close after %1 and email will be sent unless you click the cancel button.").arg( "<b>" + timer.secLeft + "s</b>")
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
property var secLeft: 0
|
||||
interval: 1000 //ms
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
secLeft--
|
||||
if (secLeft <= 0) {
|
||||
root.hide(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hide(shouldSend) {
|
||||
root.visible = false
|
||||
timer.stop()
|
||||
go.saveOutgoingNoEncPopupCoord(root.x, root.y)
|
||||
go.shouldSendAnswer(root.messageID, shouldSend)
|
||||
}
|
||||
|
||||
function show(messageID, subject) {
|
||||
root.messageID = messageID
|
||||
root.title = subject
|
||||
root.visible = true
|
||||
timer.secLeft = 10
|
||||
timer.start()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
180
internal/frontend/qml/BridgeUI/SettingsView.qml
Normal file
180
internal/frontend/qml/BridgeUI/SettingsView.qml
Normal file
@ -0,0 +1,180 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// List the settings
|
||||
|
||||
import QtQuick 2.8
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
import QtQuick.Controls 2.4
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// must have wrapper
|
||||
ScrollView {
|
||||
id: wrapper
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
clip: true
|
||||
background: Rectangle {
|
||||
color: Style.main.background
|
||||
}
|
||||
|
||||
// content
|
||||
Column {
|
||||
anchors.left : parent.left
|
||||
|
||||
ButtonIconText {
|
||||
id: cacheClear
|
||||
text: qsTr("Clear Cache", "button to clear cache in settings")
|
||||
leftIcon.text : Style.fa.times
|
||||
rightIcon {
|
||||
text : qsTr("Clear", "clickable link next to clear cache button in settings")
|
||||
color: Style.main.text
|
||||
font {
|
||||
pointSize : Style.settings.fontSize * Style.pt
|
||||
underline : true
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
dialogGlobal.state="clearCache"
|
||||
dialogGlobal.show()
|
||||
}
|
||||
}
|
||||
|
||||
ButtonIconText {
|
||||
id: cacheKeychain
|
||||
text: qsTr("Clear Keychain", "button to clear keychain in settings")
|
||||
leftIcon.text : Style.fa.chain_broken
|
||||
rightIcon {
|
||||
text : qsTr("Clear", "clickable link next to clear keychain button in settings")
|
||||
color: Style.main.text
|
||||
font {
|
||||
pointSize : Style.settings.fontSize * Style.pt
|
||||
underline : true
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
dialogGlobal.state="clearChain"
|
||||
dialogGlobal.show()
|
||||
}
|
||||
}
|
||||
|
||||
ButtonIconText {
|
||||
id: autoStart
|
||||
text: qsTr("Automatically start Bridge", "label for toggle that activates and disables the automatic start")
|
||||
leftIcon.text : Style.fa.rocket
|
||||
rightIcon {
|
||||
font.pointSize : Style.settings.toggleSize * Style.pt
|
||||
text : go.isAutoStart!=false ? Style.fa.toggle_on : Style.fa.toggle_off
|
||||
color : go.isAutoStart!=false ? Style.main.textBlue : Style.main.textDisabled
|
||||
}
|
||||
Accessible.description: (
|
||||
go.isAutoStart == false ?
|
||||
qsTr("Enable" , "Click to enable the automatic start of Bridge") :
|
||||
qsTr("Disable" , "Click to disable the automatic start of Bridge")
|
||||
) + " " + text
|
||||
onClicked: {
|
||||
go.toggleAutoStart()
|
||||
}
|
||||
}
|
||||
|
||||
ButtonIconText {
|
||||
id: advancedSettings
|
||||
property bool isAdvanced : !go.isDefaultPort
|
||||
text: qsTr("Advanced settings", "button to open the advanced settings list in the settings page")
|
||||
leftIcon.text : Style.fa.cogs
|
||||
rightIcon {
|
||||
font.pointSize : Style.settings.toggleSize * Style.pt
|
||||
text : isAdvanced!=0 ? Style.fa.chevron_circle_up : Style.fa.chevron_circle_right
|
||||
color : isAdvanced!=0 ? Style.main.textDisabled : Style.main.textBlue
|
||||
}
|
||||
|
||||
Accessible.description: (
|
||||
isAdvanced ?
|
||||
qsTr("Hide", "Click to hide the advance settings") :
|
||||
qsTr("Show", "Click to show the advance settings")
|
||||
) + " " + text
|
||||
onClicked: {
|
||||
isAdvanced = !isAdvanced
|
||||
}
|
||||
}
|
||||
|
||||
ButtonIconText {
|
||||
id: changePort
|
||||
visible: advancedSettings.isAdvanced
|
||||
text: qsTr("Change IMAP & SMTP settings", "button to change IMAP and SMTP ports in settings")
|
||||
leftIcon.text : Style.fa.plug
|
||||
rightIcon {
|
||||
text : qsTr("Change", "clickable link next to change ports button in settings")
|
||||
color: Style.main.text
|
||||
font {
|
||||
pointSize : Style.settings.fontSize * Style.pt
|
||||
underline : true
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
dialogChangePort.show()
|
||||
}
|
||||
}
|
||||
|
||||
ButtonIconText {
|
||||
id: reportNoEnc
|
||||
text: qsTr("Notification of outgoing email without encryption", "Button to set whether to report or send an email without encryption")
|
||||
visible: advancedSettings.isAdvanced
|
||||
leftIcon.text : Style.fa.ban
|
||||
rightIcon {
|
||||
font.pointSize : Style.settings.toggleSize * Style.pt
|
||||
text : go.isReportingOutgoingNoEnc ? Style.fa.toggle_on : Style.fa.toggle_off
|
||||
color : go.isReportingOutgoingNoEnc ? Style.main.textBlue : Style.main.textDisabled
|
||||
}
|
||||
Accessible.description: (
|
||||
go.isReportingOutgoingNoEnc == 0 ?
|
||||
qsTr("Enable" , "Click to report an email without encryption") :
|
||||
qsTr("Disable" , "Click to send without asking an email without encryption")
|
||||
) + " " + text
|
||||
onClicked: {
|
||||
go.toggleIsReportingOutgoingNoEnc()
|
||||
}
|
||||
}
|
||||
|
||||
ButtonIconText {
|
||||
id: allowProxy
|
||||
visible: advancedSettings.isAdvanced
|
||||
text: qsTr("Allow alternative routing", "label for toggle that allows and disallows using a proxy")
|
||||
leftIcon.text : Style.fa.rocket
|
||||
rightIcon {
|
||||
font.pointSize : Style.settings.toggleSize * Style.pt
|
||||
text : go.isProxyAllowed!=false ? Style.fa.toggle_on : Style.fa.toggle_off
|
||||
color : go.isProxyAllowed!=false ? Style.main.textBlue : Style.main.textDisabled
|
||||
}
|
||||
Accessible.description: (
|
||||
go.isProxyAllowed == false ?
|
||||
qsTr("Enable" , "Click to allow alternative routing") :
|
||||
qsTr("Disable" , "Click to disallow alternative routing")
|
||||
) + " " + text
|
||||
onClicked: {
|
||||
dialogGlobal.state="toggleAllowProxy"
|
||||
dialogGlobal.show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
16
internal/frontend/qml/BridgeUI/StatusFooter.qml
Normal file
16
internal/frontend/qml/BridgeUI/StatusFooter.qml
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
127
internal/frontend/qml/BridgeUI/VersionInfo.qml
Normal file
127
internal/frontend/qml/BridgeUI/VersionInfo.qml
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// credits
|
||||
|
||||
import QtQuick 2.8
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
Item {
|
||||
Rectangle {
|
||||
id: wrapper
|
||||
anchors.centerIn: parent
|
||||
width: 2*Style.main.width/3
|
||||
height: Style.main.height - 6*Style.dialog.titleSize
|
||||
color: "transparent"
|
||||
|
||||
Flickable {
|
||||
anchors.fill : wrapper
|
||||
contentWidth : wrapper.width
|
||||
contentHeight : content.height
|
||||
flickableDirection : Flickable.VerticalFlick
|
||||
clip : true
|
||||
|
||||
|
||||
Column {
|
||||
id: content
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: wrapper.width
|
||||
spacing: Style.dialog.spacing
|
||||
|
||||
AccessibleText {
|
||||
visible: go.changelog != ""
|
||||
anchors {
|
||||
left: parent.left
|
||||
}
|
||||
font.bold: true
|
||||
font.pointSize: Style.main.fontSize * Style.pt
|
||||
color: Style.main.text
|
||||
text: qsTr("Release notes", "list of release notes for this version of the app") + ":"
|
||||
}
|
||||
|
||||
AccessibleSelectableText {
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: Style.main.leftMargin
|
||||
}
|
||||
font {
|
||||
pointSize : Style.main.fontSize * Style.pt
|
||||
}
|
||||
width: wrapper.width - anchors.leftMargin
|
||||
onLinkActivated: {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
wrapMode: Text.Wrap
|
||||
color: Style.main.text
|
||||
text: go.changelog
|
||||
}
|
||||
|
||||
AccessibleText {
|
||||
visible: go.bugfixes != ""
|
||||
anchors {
|
||||
left: parent.left
|
||||
}
|
||||
font.bold: true
|
||||
font.pointSize: Style.main.fontSize * Style.pt
|
||||
color: Style.main.text
|
||||
text: qsTr("Fixed bugs", "list of bugs fixed for this version of the app") + ":"
|
||||
}
|
||||
|
||||
AccessibleSelectableText {
|
||||
visible: go.bugfixes!=""
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: Style.main.leftMargin
|
||||
}
|
||||
font {
|
||||
pointSize : Style.main.fontSize * Style.pt
|
||||
}
|
||||
width: wrapper.width - anchors.leftMargin
|
||||
onLinkActivated: {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
wrapMode: Text.Wrap
|
||||
color: Style.main.text
|
||||
text: go.bugfixes
|
||||
}
|
||||
|
||||
Rectangle{id:spacer; color:Style.transparent; width: Style.main.dummy; height: buttonClose.height}
|
||||
|
||||
ButtonRounded {
|
||||
id: buttonClose
|
||||
anchors.horizontalCenter: content.horizontalCenter
|
||||
text: qsTr("Close")
|
||||
onClicked: {
|
||||
dialogVersionInfo.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AccessibleSelectableText {
|
||||
anchors.horizontalCenter: content.horizontalCenter
|
||||
font {
|
||||
pointSize : Style.main.fontSize * Style.pt
|
||||
}
|
||||
color: Style.main.textDisabled
|
||||
text: "\n Current: "+go.fullversion
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
internal/frontend/qml/BridgeUI/qmldir
Normal file
15
internal/frontend/qml/BridgeUI/qmldir
Normal file
@ -0,0 +1,15 @@
|
||||
module BridgeUI
|
||||
AccountDelegate 1.0 AccountDelegate.qml
|
||||
Credits 1.0 Credits.qml
|
||||
DialogFirstStart 1.0 DialogFirstStart.qml
|
||||
DialogPortChange 1.0 DialogPortChange.qml
|
||||
DialogYesNo 1.0 DialogYesNo.qml
|
||||
DialogTLSCertInfo 1.0 DialogTLSCertInfo.qml
|
||||
HelpView 1.0 HelpView.qml
|
||||
InfoWindow 1.0 InfoWindow.qml
|
||||
MainWindow 1.0 MainWindow.qml
|
||||
ManualWindow 1.0 ManualWindow.qml
|
||||
OutgoingNoEncPopup 1.0 OutgoingNoEncPopup.qml
|
||||
SettingsView 1.0 SettingsView.qml
|
||||
StatusFooter 1.0 StatusFooter.qml
|
||||
VersionInfo 1.0 VersionInfo.qml
|
||||
314
internal/frontend/qml/Gui.qml
Normal file
314
internal/frontend/qml/Gui.qml
Normal file
@ -0,0 +1,314 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// This is main qml file
|
||||
|
||||
import QtQuick 2.8
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
// All imports from dynamic must be loaded before
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
Item {
|
||||
id: gui
|
||||
property MainWindow winMain
|
||||
property bool isFirstWindow: true
|
||||
property int warningFlags: 0
|
||||
|
||||
InfoWindow { id: infoWin }
|
||||
OutgoingNoEncPopup { id: outgoingNoEncPopup }
|
||||
BugReportWindow {
|
||||
id: bugreportWin
|
||||
clientVersion.visible : true
|
||||
|
||||
// pre-fill the form
|
||||
onPrefill : {
|
||||
userAddress.text=""
|
||||
if (accountsModel.count>0) {
|
||||
var addressList = accountsModel.get(0).aliases.split(";")
|
||||
if (addressList.length>0) {
|
||||
userAddress.text = addressList[0]
|
||||
}
|
||||
}
|
||||
clientVersion.text=go.getLastMailClient()
|
||||
}
|
||||
}
|
||||
|
||||
onWarningFlagsChanged : {
|
||||
if (gui.warningFlags==Style.okInfoBar) {
|
||||
go.normalSystray()
|
||||
} else {
|
||||
if ((gui.warningFlags & Style.errorInfoBar) == Style.errorInfoBar) {
|
||||
go.errorSystray()
|
||||
} else {
|
||||
go.highlightSystray()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Signals from Go
|
||||
Connections {
|
||||
target: go
|
||||
|
||||
onShowWindow : {
|
||||
gui.openMainWindow()
|
||||
}
|
||||
onShowHelp : {
|
||||
gui.openMainWindow(false)
|
||||
winMain.tabbar.currentIndex = 2
|
||||
winMain.showAndRise()
|
||||
}
|
||||
onShowQuit : {
|
||||
gui.openMainWindow(false)
|
||||
winMain.dialogGlobal.state="quit"
|
||||
winMain.dialogGlobal.show()
|
||||
winMain.showAndRise()
|
||||
}
|
||||
|
||||
onProcessFinished : {
|
||||
winMain.dialogGlobal.hide()
|
||||
winMain.dialogAddUser.hide()
|
||||
winMain.dialogChangePort.hide()
|
||||
infoWin.hide()
|
||||
}
|
||||
onOpenManual : Qt.openUrlExternally("http://protonmail.com/bridge")
|
||||
|
||||
onNotifyBubble : {
|
||||
gui.showBubble(tabIndex, message, true)
|
||||
}
|
||||
onSilentBubble : {
|
||||
gui.showBubble(tabIndex, message, false)
|
||||
}
|
||||
onBubbleClosed : {
|
||||
gui.warningFlags &= ~Style.warnBubbleMessage
|
||||
}
|
||||
|
||||
onSetConnectionStatus: {
|
||||
go.isConnectionOK = isAvailable
|
||||
gui.openMainWindow(false)
|
||||
if (go.isConnectionOK) {
|
||||
if( winMain.updateState=="noInternet") {
|
||||
go.setUpdateState("upToDate")
|
||||
}
|
||||
} else {
|
||||
go.setUpdateState("noInternet")
|
||||
}
|
||||
}
|
||||
|
||||
onRunCheckVersion : {
|
||||
gui.openMainWindow(false)
|
||||
go.setUpdateState("upToDate")
|
||||
winMain.dialogGlobal.state="checkUpdates"
|
||||
winMain.dialogGlobal.show()
|
||||
go.isNewVersionAvailable(showMessage)
|
||||
}
|
||||
|
||||
onSetUpdateState : {
|
||||
// once app is outdated prevent from state change
|
||||
if (winMain.updateState != "forceUpdate") {
|
||||
winMain.updateState = updateState
|
||||
}
|
||||
}
|
||||
|
||||
onSetAddAccountWarning : winMain.dialogAddUser.setWarning(message, 0)
|
||||
|
||||
|
||||
onNotifyVersionIsTheLatest : {
|
||||
go.silentBubble(2,qsTr("You have the latest version!", "notification", -1))
|
||||
}
|
||||
|
||||
onNotifyUpdate : {
|
||||
go.setUpdateState("forceUpdate")
|
||||
if (!winMain.dialogUpdate.visible) {
|
||||
gui.openMainWindow(true)
|
||||
go.runCheckVersion(false)
|
||||
winMain.dialogUpdate.show()
|
||||
}
|
||||
}
|
||||
|
||||
onNotifyLogout : {
|
||||
go.notifyBubble(0, qsTr("Account %1 has been disconnected. Please log in to continue to use the Bridge with this account.").arg(accname) )
|
||||
}
|
||||
|
||||
onNotifyAddressChanged : {
|
||||
go.notifyBubble(0, qsTr("The address list has been changed for account %1. You may need to reconfigure the settings in your email client.").arg(accname) )
|
||||
}
|
||||
|
||||
onNotifyAddressChangedLogout : {
|
||||
go.notifyBubble(0, qsTr("The address list has been changed for account %1. You have to reconfigure the settings in your email client.").arg(accname) )
|
||||
}
|
||||
|
||||
onNotifyPortIssue : { // busyPortIMAP , busyPortSMTP
|
||||
if (!busyPortIMAP && !busyPortSMTP) { // at least one must have issues to show warning
|
||||
return
|
||||
}
|
||||
gui.openMainWindow(false)
|
||||
winMain.tabbar.currentIndex=1
|
||||
go.isDefaultPort = false
|
||||
var text
|
||||
if (busyPortIMAP && busyPortSMTP) { // both have problems
|
||||
text = qsTr("The default ports used by Bridge for IMAP (%1) and SMTP (%2) are occupied by one or more other applications." , "the first part of notification text (two ports)").arg(go.getIMAPPort()).arg(go.getSMTPPort())
|
||||
text += " "
|
||||
text += qsTr("To change the ports for these servers, go to Settings -> Advanced Settings.", "the second part of notification text (two ports)")
|
||||
} else { // only one is occupied
|
||||
var server, port
|
||||
if (busyPortSMTP) {
|
||||
server = "SMTP"
|
||||
port = go.getSMTPPort()
|
||||
} else {
|
||||
server = "IMAP"
|
||||
port = go.getIMAPPort()
|
||||
}
|
||||
text = qsTr("The default port used by Bridge for %1 (%2) is occupied by another application.", "the first part of notification text (one port)").arg(server).arg(port)
|
||||
text += " "
|
||||
text += qsTr("To change the port for this server, go to Settings -> Advanced Settings.", "the second part of notification text (one port)")
|
||||
}
|
||||
go.notifyBubble(1, text )
|
||||
}
|
||||
|
||||
onNotifyKeychainRebuild : {
|
||||
go.notifyBubble(1, qsTr(
|
||||
"Your MacOS keychain is probably corrupted. Please consult the instructions in our <a href=\"https://protonmail.com/bridge/faq#c15\">FAQ</a>.",
|
||||
"notification message"
|
||||
))
|
||||
}
|
||||
|
||||
onNotifyHasNoKeychain : {
|
||||
gui.winMain.dialogGlobal.state="noKeychain"
|
||||
gui.winMain.dialogGlobal.show()
|
||||
}
|
||||
|
||||
onShowNoActiveKeyForRecipient : {
|
||||
go.notifyBubble(0, qsTr(
|
||||
"Key pinning is enabled for %1 but no active key is pinned. " +
|
||||
"You must pin the key in order to send a message to this address. " +
|
||||
"You can find instructions " +
|
||||
"<a href=\"https://protonmail.com/support/knowledge-base/key-pinning/\">here</a>."
|
||||
).arg(recipient))
|
||||
}
|
||||
|
||||
onFailedAutostartCode : {
|
||||
gui.openMainWindow(true)
|
||||
switch (code) {
|
||||
case "permission" : // linux+darwin
|
||||
case "85070005" : // windows
|
||||
go.notifyBubble(1, go.failedAutostartPerm)
|
||||
break
|
||||
case "81004003" : // windows
|
||||
go.notifyBubble(1, go.failedAutostart+" "+qsTr("Can not create instance.", "for autostart"))
|
||||
break
|
||||
case "" :
|
||||
default :
|
||||
go.notifyBubble(1, go.failedAutostart)
|
||||
}
|
||||
}
|
||||
|
||||
onShowOutgoingNoEncPopup : {
|
||||
outgoingNoEncPopup.show(messageID, subject)
|
||||
}
|
||||
|
||||
onSetOutgoingNoEncPopupCoord : {
|
||||
outgoingNoEncPopup.x = x
|
||||
outgoingNoEncPopup.y = y
|
||||
}
|
||||
|
||||
onUpdateFinished : {
|
||||
winMain.dialogUpdate.finished(hasError)
|
||||
}
|
||||
|
||||
onShowCertIssue : {
|
||||
winMain.tlsBarState="notOK"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: checkVersionTimer
|
||||
repeat : true
|
||||
triggeredOnStart: false
|
||||
interval : Style.main.verCheckRepeatTime
|
||||
onTriggered : go.runCheckVersion(false)
|
||||
}
|
||||
|
||||
function openMainWindow(showAndRise) {
|
||||
// wait and check until font is loaded
|
||||
while(true){
|
||||
if (Style.fontawesome.status == FontLoader.Loading) continue
|
||||
if (Style.fontawesome.status != FontLoader.Ready) console.log("Error while loading font")
|
||||
break
|
||||
}
|
||||
|
||||
if (typeof(showAndRise)==='undefined') {
|
||||
showAndRise = true
|
||||
}
|
||||
if (gui.winMain == null) {
|
||||
gui.winMain = Qt.createQmlObject(
|
||||
'import BridgeUI 1.0; MainWindow {visible : false}',
|
||||
gui, "winMain"
|
||||
)
|
||||
}
|
||||
if (showAndRise) {
|
||||
gui.winMain.showAndRise()
|
||||
}
|
||||
}
|
||||
|
||||
function closeMainWindow () {
|
||||
gui.winMain.hide()
|
||||
gui.winMain.destroy(5000)
|
||||
gui.winMain = null
|
||||
gui.isFirstWindow = false
|
||||
}
|
||||
|
||||
function showBubble(tabIndex, message, isWarning) {
|
||||
gui.openMainWindow(true)
|
||||
if (isWarning) {
|
||||
gui.warningFlags |= Style.warnBubbleMessage
|
||||
}
|
||||
winMain.bubbleNote.text = message
|
||||
winMain.bubbleNote.place(tabIndex)
|
||||
winMain.bubbleNote.show()
|
||||
}
|
||||
|
||||
// On start
|
||||
Component.onCompleted : {
|
||||
// set messages for translations
|
||||
go.wrongCredentials = qsTr("Incorrect username or password." , "notification", -1)
|
||||
go.wrongMailboxPassword = qsTr("Incorrect mailbox password." , "notification", -1)
|
||||
go.canNotReachAPI = qsTr("Cannot contact server, please check your internet connection." , "notification", -1)
|
||||
go.versionCheckFailed = qsTr("Version check was unsuccessful. Please try again later." , "notification", -1)
|
||||
go.credentialsNotRemoved = qsTr("Credentials could not be removed." , "notification", -1)
|
||||
go.failedAutostartPerm = qsTr("Unable to configure automatic start due to permissions settings - see <a href=\"https://protonmail.com/bridge/faq#c11\">FAQ</a> for details.", "notification", -1)
|
||||
go.failedAutostart = qsTr("Unable to configure automatic start." , "notification", -1)
|
||||
go.genericErrSeeLogs = qsTr("An error happened during procedure. See logs for more details." , "notification", -1)
|
||||
|
||||
// start window
|
||||
gui.openMainWindow(false)
|
||||
checkVersionTimer.start()
|
||||
if (go.isShownOnStart) {
|
||||
gui.winMain.showAndRise()
|
||||
}
|
||||
go.runCheckVersion(false)
|
||||
|
||||
if (go.isFreshVersion) {
|
||||
go.getLocalVersionInfo()
|
||||
gui.winMain.dialogVersionInfo.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
34
internal/frontend/qml/ProtonUI/AccessibleButton.qml
Normal file
34
internal/frontend/qml/ProtonUI/AccessibleButton.qml
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// default options to make button accessible
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.1
|
||||
import ProtonUI 1.0
|
||||
|
||||
Button {
|
||||
function clearText(value) {
|
||||
// remove font-awesome chars
|
||||
return value.replace(/[\uf000-\uf2e0]/g,'')
|
||||
}
|
||||
Accessible.onPressAction: clicked()
|
||||
Accessible.ignored: !enabled || !visible
|
||||
Accessible.name: clearText(text)
|
||||
Accessible.description: clearText(text)
|
||||
}
|
||||
|
||||
40
internal/frontend/qml/ProtonUI/AccessibleSelectableText.qml
Normal file
40
internal/frontend/qml/ProtonUI/AccessibleSelectableText.qml
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// default options to make text accessible and selectable
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
|
||||
TextEdit {
|
||||
function clearText(value) {
|
||||
// substitue the copyright symbol by the text and remove the font-awesome chars and HTML tags
|
||||
return value.replace(/\uf1f9/g,'Copyright').replace(/[\uf000-\uf2e0]/g,'').replace(/<[^>]+>/g,'')
|
||||
}
|
||||
|
||||
readOnly: true
|
||||
selectByKeyboard: true
|
||||
selectByMouse: true
|
||||
|
||||
Accessible.role: Accessible.StaticText
|
||||
Accessible.name: clearText(text)
|
||||
Accessible.description: clearText(text)
|
||||
Accessible.focusable: true
|
||||
Accessible.ignored: !enabled || !visible || text == ""
|
||||
}
|
||||
|
||||
|
||||
40
internal/frontend/qml/ProtonUI/AccessibleText.qml
Normal file
40
internal/frontend/qml/ProtonUI/AccessibleText.qml
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// default options to make text accessible
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
|
||||
Text {
|
||||
function clearText(value) {
|
||||
// substitue the copyright symbol by the text and remove the font-awesome chars and HTML tags
|
||||
return value.replace(/\uf1f9/g,'Copyright').replace(/[\uf000-\uf2e0]/g,'').replace(/<[^>]+>/g,'')
|
||||
}
|
||||
Accessible.role: Accessible.StaticText
|
||||
Accessible.name: clearText(text)
|
||||
Accessible.description: clearText(text)
|
||||
Accessible.focusable: true
|
||||
Accessible.ignored: !enabled || !visible || text == ""
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
}
|
||||
|
||||
140
internal/frontend/qml/ProtonUI/AccountView.qml
Normal file
140
internal/frontend/qml/ProtonUI/AccountView.qml
Normal file
@ -0,0 +1,140 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.1
|
||||
import ProtonUI 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
signal addAccount()
|
||||
|
||||
property alias numAccounts : listAccounts.count
|
||||
property alias model : listAccounts.model
|
||||
property alias delegate : listAccounts.delegate
|
||||
property int separatorNoAccount : viewContent.height-Style.accounts.heightFooter
|
||||
property bool hasFooter : true
|
||||
|
||||
// must have wrapper
|
||||
Rectangle {
|
||||
id: wrapper
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
color: Style.main.background
|
||||
|
||||
// content
|
||||
ListView {
|
||||
id: listAccounts
|
||||
anchors {
|
||||
top : parent.top
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
bottom : hasFooter ? addAccFooter.top : parent.bottom
|
||||
}
|
||||
orientation: ListView.Vertical
|
||||
clip: true
|
||||
cacheBuffer: 2500
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: Style.main.rightMargin/4
|
||||
}
|
||||
width: Style.main.rightMargin/3
|
||||
Accessible.ignored: true
|
||||
}
|
||||
header: Rectangle {
|
||||
width : wrapper.width
|
||||
height : root.numAccounts!=0 ? Style.accounts.heightHeader : root.separatorNoAccount
|
||||
color : "transparent"
|
||||
AccessibleText { // Placeholder on empty
|
||||
anchors {
|
||||
centerIn: parent
|
||||
}
|
||||
visible: root.numAccounts==0
|
||||
text : qsTr("No accounts added", "displayed when there are no accounts added")
|
||||
font.pointSize : Style.main.fontSize * Style.pt
|
||||
color : Style.main.textDisabled
|
||||
}
|
||||
Text { // Account
|
||||
anchors {
|
||||
left : parent.left
|
||||
leftMargin : Style.main.leftMargin
|
||||
verticalCenter : parent.verticalCenter
|
||||
}
|
||||
visible: root.numAccounts!=0
|
||||
font.bold : true
|
||||
font.pointSize : Style.main.fontSize * Style.pt
|
||||
text : qsTr("ACCOUNT", "title of column that displays account name")
|
||||
color : Style.main.textDisabled
|
||||
}
|
||||
Text { // Status
|
||||
anchors {
|
||||
left : parent.left
|
||||
leftMargin : Style.accounts.leftMargin2
|
||||
verticalCenter : parent.verticalCenter
|
||||
}
|
||||
visible: root.numAccounts!=0
|
||||
font.bold : true
|
||||
font.pointSize : Style.main.fontSize * Style.pt
|
||||
text : qsTr("STATUS", "title of column that displays connected or disconnected status")
|
||||
color : Style.main.textDisabled
|
||||
}
|
||||
Text { // Actions
|
||||
anchors {
|
||||
left : parent.left
|
||||
leftMargin : Style.accounts.leftMargin3
|
||||
verticalCenter : parent.verticalCenter
|
||||
}
|
||||
visible: root.numAccounts!=0
|
||||
font.bold : true
|
||||
font.pointSize : Style.main.fontSize * Style.pt
|
||||
text : qsTr("ACTIONS", "title of column that displays log out and log in actions for each account")
|
||||
color : Style.main.textDisabled
|
||||
}
|
||||
// line
|
||||
Rectangle {
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
bottom : parent.bottom
|
||||
}
|
||||
visible: root.numAccounts!=0
|
||||
color: Style.accounts.line
|
||||
height: Style.accounts.heightLine
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AddAccountBar {
|
||||
id: addAccFooter
|
||||
visible: hasFooter
|
||||
anchors {
|
||||
left : parent.left
|
||||
bottom : parent.bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: StandardKey.SelectAll
|
||||
onActivated: root.addAccount()
|
||||
}
|
||||
}
|
||||
69
internal/frontend/qml/ProtonUI/AddAccountBar.qml
Normal file
69
internal/frontend/qml/ProtonUI/AddAccountBar.qml
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Bar with add account button and help
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
|
||||
|
||||
Rectangle {
|
||||
width : parent.width
|
||||
height : Style.accounts.heightFooter
|
||||
color: "transparent"
|
||||
Rectangle {
|
||||
anchors {
|
||||
top : parent.top
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
}
|
||||
height: Style.accounts.heightLine
|
||||
color: Style.accounts.line
|
||||
}
|
||||
ClickIconText {
|
||||
id: buttonAddAccount
|
||||
anchors {
|
||||
left : parent.left
|
||||
leftMargin : Style.main.leftMargin
|
||||
verticalCenter : parent.verticalCenter
|
||||
}
|
||||
textColor : Style.main.textBlue
|
||||
iconText : Style.fa.plus_circle
|
||||
text : qsTr("Add Account", "begins the flow to log in to an account that is not yet listed")
|
||||
textBold : true
|
||||
onClicked : root.addAccount()
|
||||
Accessible.description: {
|
||||
if (gui.winMain!=null) {
|
||||
return text + (gui.winMain.addAccountTip.visible? ", "+gui.winMain.addAccountTip.text : "")
|
||||
}
|
||||
return buttonAddAccount.text
|
||||
}
|
||||
}
|
||||
ClickIconText {
|
||||
id: buttonHelp
|
||||
anchors {
|
||||
right : parent.right
|
||||
rightMargin : Style.main.rightMargin
|
||||
verticalCenter : parent.verticalCenter
|
||||
}
|
||||
textColor : Style.main.textDisabled
|
||||
iconText : Style.fa.question_circle
|
||||
text : qsTr("Help", "directs the user to the online user guide")
|
||||
textBold : true
|
||||
onClicked : go.openManual()
|
||||
}
|
||||
}
|
||||
170
internal/frontend/qml/ProtonUI/BubbleNote.qml
Normal file
170
internal/frontend/qml/ProtonUI/BubbleNote.qml
Normal file
@ -0,0 +1,170 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Notify user
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
property int posx // x-coordinate of triangle
|
||||
property bool isTriangleBelow
|
||||
property string text
|
||||
property alias bubbleColor: bubble.color
|
||||
anchors {
|
||||
top : tabbar.bottom
|
||||
left : tabbar.left
|
||||
leftMargin : {
|
||||
// position of bubble calculated from posx
|
||||
return Math.max(
|
||||
Style.main.leftMargin, // keep minimal left margin
|
||||
Math.min(
|
||||
root.posx - root.width/2, // fit triangle in the middle if possible
|
||||
tabbar.width - root.width - Style.main.rightMargin // keep minimal right margin
|
||||
)
|
||||
)
|
||||
}
|
||||
topMargin: 0
|
||||
}
|
||||
height : triangle.height + bubble.height
|
||||
width : bubble.width
|
||||
color : "transparent"
|
||||
visible : false
|
||||
|
||||
|
||||
Rectangle {
|
||||
id : triangle
|
||||
anchors {
|
||||
top : root.isTriangleBelow ? undefined : root.top
|
||||
bottom : root.isTriangleBelow ? root.bottom : undefined
|
||||
bottomMargin : 1*Style.px
|
||||
left : root.left
|
||||
leftMargin : root.posx - triangle.width/2 - root.anchors.leftMargin
|
||||
}
|
||||
width: 2*Style.tabbar.heightTriangle+2
|
||||
height: Style.tabbar.heightTriangle
|
||||
color: "transparent"
|
||||
Canvas {
|
||||
anchors.fill: parent
|
||||
rotation: root.isTriangleBelow ? 180 : 0
|
||||
onPaint: {
|
||||
var ctx = getContext("2d")
|
||||
ctx.fillStyle = bubble.color
|
||||
ctx.moveTo(0 , height)
|
||||
ctx.lineTo(width/2, 0)
|
||||
ctx.lineTo(width , height)
|
||||
ctx.closePath()
|
||||
ctx.fill()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: bubble
|
||||
anchors {
|
||||
top: root.top
|
||||
left: root.left
|
||||
topMargin: (root.isTriangleBelow ? 0 : triangle.height)
|
||||
}
|
||||
width : mainText.contentWidth + Style.main.leftMargin + Style.main.rightMargin
|
||||
height : 2*Style.main.fontSize
|
||||
radius : Style.bubble.radius
|
||||
color : Style.bubble.background
|
||||
|
||||
AccessibleText {
|
||||
id: mainText
|
||||
anchors {
|
||||
horizontalCenter : parent.horizontalCenter
|
||||
top: parent.top
|
||||
topMargin : Style.main.fontSize
|
||||
}
|
||||
|
||||
text: "<html><style>a { color: "+Style.main.textBlue+";}</style>"+root.text+"<html>"
|
||||
width : Style.bubble.width - ( Style.main.leftMargin + Style.main.rightMargin )
|
||||
font.pointSize: Style.main.fontSize * Style.pt
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
textFormat: Text.RichText
|
||||
wrapMode: Text.WordWrap
|
||||
color: Style.bubble.text
|
||||
onLinkActivated: {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: mainText
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
|
||||
Accessible.name: qsTr("Message")
|
||||
Accessible.description: root.text
|
||||
}
|
||||
|
||||
ButtonRounded {
|
||||
id: okButton
|
||||
visible: !root.isTriangleBelow
|
||||
anchors {
|
||||
bottom : parent.bottom
|
||||
horizontalCenter : parent.horizontalCenter
|
||||
bottomMargin : Style.main.fontSize
|
||||
}
|
||||
text: qsTr("Okay", "confirms and dismisses a notification")
|
||||
height: Style.main.fontSize*2
|
||||
color_main: Style.main.text
|
||||
color_minor: Style.main.textBlue
|
||||
isOpaque: true
|
||||
onClicked: hide()
|
||||
}
|
||||
}
|
||||
|
||||
function place(index) {
|
||||
if (index < 0) {
|
||||
// add accounts
|
||||
root.isTriangleBelow = true
|
||||
bubble.height = 3.25*Style.main.fontSize
|
||||
root.posx = 2*Style.main.leftMargin
|
||||
bubble.width = mainText.contentWidth - Style.main.leftMargin
|
||||
} else {
|
||||
root.isTriangleBelow = false
|
||||
bubble.height = (
|
||||
bubble.anchors.topMargin + // from top
|
||||
mainText.contentHeight + // the text content
|
||||
Style.main.fontSize + // gap between button
|
||||
okButton.height + okButton.anchors.bottomMargin // from bottom and button
|
||||
)
|
||||
if (index < 3) {
|
||||
// possition accordig to top tab
|
||||
var margin = Style.main.leftMargin + Style.tabbar.widthButton/2
|
||||
root.posx = margin + index*tabbar.spacing
|
||||
} else {
|
||||
// quit button
|
||||
root.posx = tabbar.width - 2*Style.main.rightMargin
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function show() {
|
||||
root.visible=true
|
||||
gui.winMain.activeContent = false
|
||||
}
|
||||
|
||||
function hide() {
|
||||
root.visible=false
|
||||
go.bubbleClosed()
|
||||
gui.winMain.activeContent = true
|
||||
gui.winMain.tabbar.focusButton()
|
||||
}
|
||||
}
|
||||
337
internal/frontend/qml/ProtonUI/BugReportWindow.qml
Normal file
337
internal/frontend/qml/ProtonUI/BugReportWindow.qml
Normal file
@ -0,0 +1,337 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Window for sending a bug report
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls 2.1
|
||||
import ProtonUI 1.0
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
Window {
|
||||
id:root
|
||||
property alias userAddress : userAddress
|
||||
property alias clientVersion : clientVersion
|
||||
|
||||
width : Style.bugreport.width
|
||||
height : Style.bugreport.height
|
||||
minimumWidth : Style.bugreport.width
|
||||
maximumWidth : Style.bugreport.width
|
||||
minimumHeight : Style.bugreport.height
|
||||
maximumHeight : Style.bugreport.height
|
||||
|
||||
property color inputBorderColor : Style.main.text
|
||||
|
||||
color : "transparent"
|
||||
flags : Qt.Window | Qt.Dialog | Qt.FramelessWindowHint
|
||||
title : "ProtonMail Bridge - Bug report"
|
||||
visible : false
|
||||
|
||||
WindowTitleBar {
|
||||
id: titleBar
|
||||
window: root
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id:background
|
||||
color: Style.main.background
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
top : titleBar.bottom
|
||||
bottom : parent.bottom
|
||||
}
|
||||
border {
|
||||
width: Style.main.border
|
||||
color: Style.tabbar.background
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id:content
|
||||
anchors {
|
||||
fill : parent
|
||||
leftMargin : Style.main.leftMargin
|
||||
rightMargin : Style.main.rightMargin
|
||||
bottomMargin : Style.main.rightMargin
|
||||
topMargin : Style.main.rightMargin + titleBar.height
|
||||
}
|
||||
color: "transparent"
|
||||
|
||||
// Description in flickable
|
||||
Flickable {
|
||||
id: descripWrapper
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
}
|
||||
height: content.height - (
|
||||
(clientVersion.visible ? clientVersion.height + Style.dialog.fontSize : 0) +
|
||||
userAddress.height + Style.dialog.fontSize +
|
||||
securityNote.contentHeight + Style.dialog.fontSize +
|
||||
cancelButton.height + Style.dialog.fontSize
|
||||
)
|
||||
clip: true
|
||||
contentWidth : width
|
||||
contentHeight : height
|
||||
|
||||
TextArea.flickable: TextArea {
|
||||
id: description
|
||||
focus: true
|
||||
wrapMode: TextEdit.Wrap
|
||||
placeholderText: qsTr ("Please briefly describe the bug(s) you have encountered...", "bug report instructions")
|
||||
background : Rectangle {
|
||||
color : Style.dialog.background
|
||||
radius: Style.dialog.radiusButton
|
||||
border {
|
||||
color : root.inputBorderColor
|
||||
width : Style.dialog.borderInput
|
||||
}
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: FastBlur {
|
||||
anchors.fill: parent
|
||||
radius: 8 * Style.px
|
||||
}
|
||||
}
|
||||
color: Style.main.text
|
||||
font.pointSize: Style.dialog.fontSize * Style.pt
|
||||
selectionColor: Style.main.textBlue
|
||||
selectByKeyboard: true
|
||||
selectByMouse: true
|
||||
KeyNavigation.tab: clientVersion
|
||||
KeyNavigation.priority: KeyNavigation.BeforeItem
|
||||
}
|
||||
|
||||
ScrollBar.vertical : ScrollBar{}
|
||||
}
|
||||
|
||||
// Client
|
||||
TextLabel {
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: descripWrapper.bottom
|
||||
topMargin: Style.dialog.fontSize
|
||||
}
|
||||
visible: clientVersion.visible
|
||||
width: parent.width/2.618
|
||||
text: qsTr ("Email client:", "in the bug report form, which third-party email client is being used")
|
||||
font.pointSize: Style.dialog.fontSize * Style.pt
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: clientVersion
|
||||
anchors {
|
||||
right: parent.right
|
||||
top: descripWrapper.bottom
|
||||
topMargin: Style.dialog.fontSize
|
||||
}
|
||||
placeholderText: qsTr("e.g. Thunderbird", "in the bug report form, placeholder text for email client")
|
||||
width: parent.width/1.618
|
||||
|
||||
color : Style.dialog.text
|
||||
selectionColor : Style.main.textBlue
|
||||
selectByMouse : true
|
||||
font.pointSize : Style.dialog.fontSize * Style.pt
|
||||
padding : Style.dialog.radiusButton
|
||||
|
||||
background: Rectangle {
|
||||
color : Style.dialog.background
|
||||
radius: Style.dialog.radiusButton
|
||||
border {
|
||||
color : root.inputBorderColor
|
||||
width : Style.dialog.borderInput
|
||||
}
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: FastBlur {
|
||||
anchors.fill: parent
|
||||
radius: 8 * Style.px
|
||||
}
|
||||
}
|
||||
onAccepted: userAddress.focus = true
|
||||
}
|
||||
|
||||
// Address
|
||||
TextLabel {
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: clientVersion.visible ? clientVersion.bottom : descripWrapper.bottom
|
||||
topMargin: Style.dialog.fontSize
|
||||
}
|
||||
color: Style.dialog.text
|
||||
width: parent.width/2.618
|
||||
text: qsTr ("Contact email:", "in the bug report form, an email to contact the user at")
|
||||
font.pointSize: Style.dialog.fontSize * Style.pt
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: userAddress
|
||||
anchors {
|
||||
right: parent.right
|
||||
top: clientVersion.visible ? clientVersion.bottom : descripWrapper.bottom
|
||||
topMargin: Style.dialog.fontSize
|
||||
}
|
||||
placeholderText: "benjerry@protonmail.com"
|
||||
width: parent.width/1.618
|
||||
|
||||
color : Style.dialog.text
|
||||
selectionColor : Style.main.textBlue
|
||||
selectByMouse : true
|
||||
font.pointSize : Style.dialog.fontSize * Style.pt
|
||||
padding : Style.dialog.radiusButton
|
||||
|
||||
background: Rectangle {
|
||||
color : Style.dialog.background
|
||||
radius: Style.dialog.radiusButton
|
||||
border {
|
||||
color : root.inputBorderColor
|
||||
width : Style.dialog.borderInput
|
||||
}
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: FastBlur {
|
||||
anchors.fill: parent
|
||||
radius: 8 * Style.px
|
||||
}
|
||||
}
|
||||
onAccepted: root.submit()
|
||||
}
|
||||
|
||||
// Note
|
||||
AccessibleText {
|
||||
id: securityNote
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: userAddress.bottom
|
||||
topMargin: Style.dialog.fontSize
|
||||
}
|
||||
wrapMode: Text.Wrap
|
||||
color: Style.dialog.text
|
||||
font.pointSize : Style.dialog.fontSize * Style.pt
|
||||
text:
|
||||
"<span style='font-family: " + Style.fontawesome.name + "'>" + Style.fa.exclamation_triangle + "</span> " +
|
||||
qsTr("Bug reports are not end-to-end encrypted!", "The first part of warning in bug report form") + " " +
|
||||
qsTr("Please do not send any sensitive information.", "The second part of warning in bug report form") + " " +
|
||||
qsTr("Contact us at security@protonmail.com for critical security issues.", "The third part of warning in bug report form")
|
||||
}
|
||||
|
||||
// buttons
|
||||
ButtonRounded {
|
||||
id: cancelButton
|
||||
anchors {
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
}
|
||||
fa_icon: Style.fa.times
|
||||
text: qsTr ("Cancel", "dismisses current action")
|
||||
onClicked : root.hide()
|
||||
}
|
||||
ButtonRounded {
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
isOpaque: true
|
||||
color_main: "white"
|
||||
color_minor: Style.main.textBlue
|
||||
fa_icon: Style.fa.send
|
||||
text: qsTr ("Send", "button sends bug report")
|
||||
onClicked : root.submit()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: notification
|
||||
property bool isOK: true
|
||||
visible: false
|
||||
color: background.color
|
||||
anchors.fill: background
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
color: Style.dialog.text
|
||||
width: background.width*0.6180
|
||||
text: notification.isOK ?
|
||||
qsTr ( "Bug report successfully sent." , "notification message about bug sending" ) :
|
||||
qsTr ( "Unable to submit bug report." , "notification message about bug sending" )
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pointSize: Style.dialog.titleSize * Style.pt
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: notificationTimer
|
||||
interval: 3000
|
||||
repeat: false
|
||||
onTriggered : {
|
||||
notification.visible=false
|
||||
if (notification.isOK) root.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function submit(){
|
||||
if(root.areInputsOK()){
|
||||
root.notify(go.sendBug(description.text, clientVersion.text, userAddress.text ))
|
||||
}
|
||||
}
|
||||
|
||||
function isEmpty(input){
|
||||
if (input.text=="") {
|
||||
input.focus=true
|
||||
input.placeholderText = qsTr("Field required", "a field that must be filled in to submit form")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function areInputsOK() {
|
||||
var isOK = true
|
||||
if (isEmpty(userAddress)) { isOK=false }
|
||||
if (clientVersion.visible && isEmpty(clientVersion)) { isOK=false }
|
||||
if (isEmpty(description)) { isOK=false }
|
||||
return isOK
|
||||
}
|
||||
|
||||
function clear() {
|
||||
description.text = ""
|
||||
clientVersion.text = ""
|
||||
notification.visible = false
|
||||
}
|
||||
|
||||
signal prefill()
|
||||
|
||||
function notify(isOK){
|
||||
notification.isOK = isOK
|
||||
notification.visible = true
|
||||
notificationTimer.start()
|
||||
}
|
||||
|
||||
|
||||
function show() {
|
||||
prefill()
|
||||
root.visible=true
|
||||
}
|
||||
|
||||
function hide() {
|
||||
clear()
|
||||
root.visible=false
|
||||
}
|
||||
}
|
||||
100
internal/frontend/qml/ProtonUI/ButtonIconText.qml
Normal file
100
internal/frontend/qml/ProtonUI/ButtonIconText.qml
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Button with full window width containing two icons (left and right) and text
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.1
|
||||
import ProtonUI 1.0
|
||||
|
||||
AccessibleButton {
|
||||
id: root
|
||||
property alias leftIcon : leftIcon
|
||||
property alias rightIcon : rightIcon
|
||||
property alias main : mainText
|
||||
|
||||
// dimensions
|
||||
width : viewContent.width
|
||||
height : Style.main.heightRow
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
leftPadding: Style.main.leftMargin
|
||||
rightPadding: Style.main.rightMargin
|
||||
|
||||
background : Rectangle{
|
||||
color: Qt.lighter(Style.main.background, root.hovered || root.activeFocus ? ( root.pressed ? 1.2: 1.1) :1.0)
|
||||
// line
|
||||
Rectangle {
|
||||
anchors.bottom : parent.bottom
|
||||
width : parent.width
|
||||
height : Style.main.heightLine
|
||||
color : Style.main.line
|
||||
}
|
||||
// pointing cursor
|
||||
MouseArea {
|
||||
anchors.fill : parent
|
||||
cursorShape : Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
}
|
||||
|
||||
contentItem : Rectangle {
|
||||
color: "transparent"
|
||||
// Icon left
|
||||
Text {
|
||||
id: leftIcon
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
left : parent.left
|
||||
}
|
||||
font {
|
||||
family : Style.fontawesome.name
|
||||
pointSize : Style.settings.iconSize * Style.pt
|
||||
}
|
||||
color : Style.main.textBlue
|
||||
text : Style.fa.hashtag
|
||||
}
|
||||
|
||||
// Icon/Text right
|
||||
Text {
|
||||
id: rightIcon
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
right : parent.right
|
||||
}
|
||||
font {
|
||||
family : Style.fontawesome.name
|
||||
pointSize : Style.settings.iconSize * Style.pt
|
||||
}
|
||||
color : Style.main.textBlue
|
||||
text : Style.fa.hashtag
|
||||
}
|
||||
|
||||
// Label
|
||||
Text {
|
||||
id: mainText
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
left : leftIcon.right
|
||||
leftMargin : leftIcon.text!="" ? Style.main.leftMargin : 0
|
||||
}
|
||||
font.pointSize : Style.settings.fontSize * Style.pt
|
||||
color : Style.main.text
|
||||
text : root.text
|
||||
}
|
||||
}
|
||||
}
|
||||
92
internal/frontend/qml/ProtonUI/ButtonRounded.qml
Normal file
92
internal/frontend/qml/ProtonUI/ButtonRounded.qml
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Classic button with icon and text
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.1
|
||||
import QtGraphicalEffects 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
AccessibleButton {
|
||||
id: root
|
||||
property string fa_icon : ""
|
||||
property color color_main : Style.dialog.text
|
||||
property color color_minor : "transparent"
|
||||
property bool isOpaque : false
|
||||
|
||||
text : "undef"
|
||||
state : root.hovered || root.activeFocus ? "hover" : "normal"
|
||||
width : Style.dialog.widthButton
|
||||
height : Style.dialog.heightButton
|
||||
scale : root.pressed ? 0.96 : 1.00
|
||||
|
||||
background: Rectangle {
|
||||
border {
|
||||
color : root.color_main
|
||||
width : root.isOpaque ? 0 : Style.dialog.borderButton
|
||||
}
|
||||
radius : Style.dialog.radiusButton
|
||||
color : root.isOpaque ? root.color_minor : "transparent"
|
||||
|
||||
MouseArea {
|
||||
anchors.fill : parent
|
||||
cursorShape : Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Rectangle {
|
||||
color: "transparent"
|
||||
|
||||
Row {
|
||||
id: mainText
|
||||
anchors.centerIn: parent
|
||||
spacing: 0
|
||||
|
||||
Text {
|
||||
font {
|
||||
pointSize : Style.dialog.fontSize * Style.pt
|
||||
family : Style.fontawesome.name
|
||||
}
|
||||
color : color_main
|
||||
text : root.fa_icon=="" ? "" : root.fa_icon + " "
|
||||
}
|
||||
|
||||
Text {
|
||||
font {
|
||||
pointSize : Style.dialog.fontSize * Style.pt
|
||||
}
|
||||
color : color_main
|
||||
text : root.text
|
||||
}
|
||||
}
|
||||
|
||||
Glow {
|
||||
id: mainTextEffect
|
||||
anchors.fill : mainText
|
||||
source: mainText
|
||||
color: color_main
|
||||
opacity: 0.33
|
||||
}
|
||||
}
|
||||
|
||||
states :[
|
||||
State {name: "normal"; PropertyChanges{ target: mainTextEffect; radius: 0 ; visible: false } },
|
||||
State {name: "hover" ; PropertyChanges{ target: mainTextEffect; radius: 3*Style.px ; visible: true } }
|
||||
]
|
||||
}
|
||||
55
internal/frontend/qml/ProtonUI/CheckBoxLabel.qml
Normal file
55
internal/frontend/qml/ProtonUI/CheckBoxLabel.qml
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// input for date range
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.2
|
||||
import ProtonUI 1.0
|
||||
|
||||
CheckBox {
|
||||
id: root
|
||||
spacing: Style.dialog.spacing
|
||||
padding: 0
|
||||
property color textColor : Style.main.text
|
||||
property color checkedColor : Style.main.textBlue
|
||||
property color uncheckedColor : Style.main.textInactive
|
||||
property string checkedSymbol : Style.fa.check_square_o
|
||||
property string uncheckedSymbol : Style.fa.square_o
|
||||
background: Rectangle {
|
||||
color: Style.transparent
|
||||
}
|
||||
indicator: Text {
|
||||
text : root.checked ? root.checkedSymbol : root.uncheckedSymbol
|
||||
color : root.checked ? root.checkedColor : root.uncheckedColor
|
||||
font {
|
||||
pointSize : Style.dialog.iconSize * Style.pt
|
||||
family : Style.fontawesome.name
|
||||
}
|
||||
}
|
||||
contentItem: Text {
|
||||
id: label
|
||||
text : root.text
|
||||
color : root.textColor
|
||||
font {
|
||||
pointSize: Style.dialog.fontSize * Style.pt
|
||||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
leftPadding: Style.dialog.iconSize + root.spacing
|
||||
}
|
||||
}
|
||||
98
internal/frontend/qml/ProtonUI/ClickIconText.qml
Normal file
98
internal/frontend/qml/ProtonUI/ClickIconText.qml
Normal file
@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// No border button with icon
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.1
|
||||
import ProtonUI 1.0
|
||||
|
||||
AccessibleButton {
|
||||
id: root
|
||||
|
||||
property string iconText : Style.fa.hashtag
|
||||
property color textColor : Style.main.text
|
||||
property int fontSize : Style.main.fontSize
|
||||
property int iconSize : Style.main.iconSize
|
||||
property int margin : iconText!="" ? Style.main.leftMarginButton : 0.0
|
||||
property bool iconOnRight : false
|
||||
property bool textBold : false
|
||||
property bool textUnderline : false
|
||||
|
||||
|
||||
TextMetrics {
|
||||
id: metrics
|
||||
text: root.text
|
||||
font: showText.font
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: metricsIcon
|
||||
text : root.iconText
|
||||
font : showIcon.font
|
||||
}
|
||||
|
||||
scale : root.pressed ? 0.96 : root.activeFocus ? 1.05 : 1.0
|
||||
height : Math.max(metrics.height, metricsIcon.height)
|
||||
width : metricsIcon.width*1.5 + margin + metrics.width + 4.0
|
||||
padding : 0.0
|
||||
|
||||
background : Rectangle {
|
||||
color: Style.transparent
|
||||
MouseArea {
|
||||
anchors.fill : parent
|
||||
cursorShape : Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
}
|
||||
|
||||
contentItem : Rectangle {
|
||||
color: Style.transparent
|
||||
Text {
|
||||
id: showIcon
|
||||
anchors {
|
||||
left : iconOnRight ? showText.right : parent.left
|
||||
leftMargin : iconOnRight ? margin : 0
|
||||
verticalCenter : parent.verticalCenter
|
||||
}
|
||||
font {
|
||||
pointSize : iconSize * Style.pt
|
||||
family : Style.fontawesome.name
|
||||
}
|
||||
color : textColor
|
||||
text : root.iconText
|
||||
}
|
||||
|
||||
Text {
|
||||
id: showText
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
left : iconOnRight ? parent.left : showIcon.right
|
||||
leftMargin : iconOnRight ? 0 : margin
|
||||
}
|
||||
color : textColor
|
||||
font {
|
||||
pointSize : root.fontSize * Style.pt
|
||||
bold: root.textBold
|
||||
underline: root.textUnderline
|
||||
}
|
||||
text : root.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
147
internal/frontend/qml/ProtonUI/Dialog.qml
Normal file
147
internal/frontend/qml/ProtonUI/Dialog.qml
Normal file
@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2020 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 QtQuick.Layouts 1.3
|
||||
import ProtonUI 1.0
|
||||
|
||||
|
||||
StackLayout {
|
||||
id: root
|
||||
property string title : "title"
|
||||
property string subtitle : ""
|
||||
property alias timer : timer
|
||||
property alias warning : warningText
|
||||
property bool isDialogBusy : false
|
||||
property real titleHeight : 2*titleText.anchors.topMargin + titleText.height + (warningText.visible ? warningText.anchors.topMargin + warningText.height : 0)
|
||||
property Item background : Rectangle {
|
||||
parent: root
|
||||
width: root.width
|
||||
height: root.height
|
||||
color : Style.dialog.background
|
||||
visible: root.visible
|
||||
z: -1
|
||||
|
||||
AccessibleText {
|
||||
id: titleText
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
topMargin: Style.dialog.titleSize
|
||||
}
|
||||
font.pointSize : Style.dialog.titleSize * Style.pt
|
||||
color : Style.dialog.text
|
||||
text : root.title
|
||||
}
|
||||
|
||||
AccessibleText {
|
||||
id: subtitleText
|
||||
anchors {
|
||||
top: titleText.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
font.pointSize : Style.dialog.fontSize * Style.pt
|
||||
color : Style.dialog.text
|
||||
text : root.subtitle
|
||||
visible : root.subtitle != ""
|
||||
}
|
||||
|
||||
AccessibleText {
|
||||
id:warningText
|
||||
anchors {
|
||||
top: subtitleText.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
font {
|
||||
bold: true
|
||||
pointSize: Style.dialog.fontSize * Style.pt
|
||||
}
|
||||
text : ""
|
||||
color: Style.main.textBlue
|
||||
visible: false
|
||||
}
|
||||
|
||||
// prevent any action below
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
ClickIconText {
|
||||
anchors {
|
||||
top: parent.top
|
||||
right: parent.right
|
||||
topMargin: Style.dialog.titleSize
|
||||
rightMargin: Style.dialog.titleSize
|
||||
}
|
||||
visible : !isDialogBusy
|
||||
iconText : Style.fa.times
|
||||
text : ""
|
||||
onClicked : root.hide()
|
||||
Accessible.description : qsTr("Close dialog %1", "Click to exit modal.").arg(root.title)
|
||||
}
|
||||
}
|
||||
|
||||
Accessible.role: Accessible.Grouping
|
||||
Accessible.name: title
|
||||
Accessible.description: title
|
||||
Accessible.focusable: true
|
||||
|
||||
|
||||
visible : false
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
top : titleBar.bottom
|
||||
bottom : parent.bottom
|
||||
}
|
||||
currentIndex : 0
|
||||
|
||||
|
||||
signal show()
|
||||
signal hide()
|
||||
|
||||
function incrementCurrentIndex() {
|
||||
root.currentIndex++
|
||||
}
|
||||
|
||||
function decrementCurrentIndex() {
|
||||
root.currentIndex--
|
||||
}
|
||||
|
||||
onShow: {
|
||||
root.visible = true
|
||||
root.forceActiveFocus()
|
||||
}
|
||||
|
||||
onHide: {
|
||||
root.timer.stop()
|
||||
root.currentIndex=0
|
||||
root.visible = false
|
||||
root.timer.stop()
|
||||
gui.winMain.tabbar.focusButton()
|
||||
}
|
||||
|
||||
// QTimer is recommeded solution for creating trheads : http://doc.qt.io/qt-5/qtquick-threading-example.html
|
||||
Timer {
|
||||
id: timer
|
||||
interval: 300 // wait for transistion
|
||||
repeat: false
|
||||
}
|
||||
}
|
||||
464
internal/frontend/qml/ProtonUI/DialogAddUser.qml
Normal file
464
internal/frontend/qml/ProtonUI/DialogAddUser.qml
Normal file
@ -0,0 +1,464 @@
|
||||
// Copyright (c) 2020 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
|
||||
height : root.height/2 - (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()
|
||||
}
|
||||
}
|
||||
}
|
||||
148
internal/frontend/qml/ProtonUI/DialogConnectionTroubleshoot.qml
Normal file
148
internal/frontend/qml/ProtonUI/DialogConnectionTroubleshoot.qml
Normal file
@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2020 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 Yes/No buttons
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
|
||||
title : qsTr(
|
||||
"Common connection problems and solutions",
|
||||
"Title of the network troubleshooting modal"
|
||||
)
|
||||
isDialogBusy: false // can close
|
||||
property var parContent : [
|
||||
[
|
||||
qsTr("Allow alternative routing" , "Paragraph title"),
|
||||
qsTr(
|
||||
"In case Proton sites are blocked, this setting allows Bridge "+
|
||||
"to try alternative network routing to reach Proton, which can "+
|
||||
"be useful for bypassing firewalls or network issues. We recommend "+
|
||||
"keeping this setting on for greater reliability. "+
|
||||
'<a href="https://protonmail.com/blog/anti-censorship-alternative-routing/">Learn more</a>'+
|
||||
" and "+
|
||||
'<a href="showProxy">enable here</a>'+
|
||||
".",
|
||||
"Paragraph content"
|
||||
),
|
||||
],
|
||||
|
||||
[
|
||||
qsTr("No internet connection" , "Paragraph title"),
|
||||
qsTr(
|
||||
"Please make sure that your internet connection is working.",
|
||||
"Paragraph content"
|
||||
),
|
||||
],
|
||||
|
||||
[
|
||||
qsTr("Internet Service Provider (ISP) problem" , "Paragraph title"),
|
||||
qsTr(
|
||||
"Try connecting to Proton from a different network (or use "+
|
||||
'<a href="https://protonvpn.com/">ProtonVPN</a>'+
|
||||
" or "+
|
||||
'<a href="https://torproject.org/">Tor</a>'+
|
||||
").",
|
||||
"Paragraph content"
|
||||
),
|
||||
],
|
||||
|
||||
[
|
||||
qsTr("Government block" , "Paragraph title"),
|
||||
qsTr(
|
||||
"Your country may be blocking access to Proton. Try using "+
|
||||
'<a href="https://protonvpn.com/">ProtonVPN</a>'+
|
||||
" (or any other VPN) or "+
|
||||
'<a href="https://torproject.org/">Tor</a>'+
|
||||
".",
|
||||
"Paragraph content"
|
||||
),
|
||||
],
|
||||
|
||||
[
|
||||
qsTr("Antivirus interference" , "Paragraph title"),
|
||||
qsTr(
|
||||
"Temporarily disable or remove your antivirus software.",
|
||||
"Paragraph content"
|
||||
),
|
||||
],
|
||||
|
||||
[
|
||||
qsTr("Proxy/Firewall interference" , "Paragraph title"),
|
||||
qsTr(
|
||||
"Disable any proxies or firewalls, or contact your network administrator.",
|
||||
"Paragraph content"
|
||||
),
|
||||
],
|
||||
|
||||
[
|
||||
qsTr("Still can’t find a solution" , "Paragraph title"),
|
||||
qsTr(
|
||||
"Contact us directly through our "+
|
||||
'<a href="https://protonmail.com/support-form">support form</a>'+
|
||||
", email (support@protonmail.com), or "+
|
||||
'<a href="https://twitter.com/ProtonMail">Twitter</a>'+
|
||||
".",
|
||||
"Paragraph content"
|
||||
),
|
||||
],
|
||||
|
||||
[
|
||||
qsTr("Proton is down" , "Paragraph title"),
|
||||
qsTr(
|
||||
"Check "+
|
||||
'<a href="https://protonstatus.com/">Proton Status</a>'+
|
||||
" for our system status.",
|
||||
"Paragraph content"
|
||||
),
|
||||
],
|
||||
|
||||
]
|
||||
|
||||
Item {
|
||||
AccessibleText {
|
||||
anchors.centerIn: parent
|
||||
color: Style.old.pm_white
|
||||
linkColor: color
|
||||
width: parent.width - 50 * Style.px
|
||||
wrapMode: Text.WordWrap
|
||||
font.pointSize: Style.main.fontSize*Style.pt
|
||||
onLinkActivated: {
|
||||
if (link=="showProxy") {
|
||||
dialogGlobal.state= "toggleAllowProxy"
|
||||
dialogGlobal.show()
|
||||
} else {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
text: {
|
||||
var content=""
|
||||
for (var i=0; i<root.parContent.length; i++) {
|
||||
var par = root.parContent[i]
|
||||
content += "<p>"
|
||||
content += "<b>"+par[0]+":</b> "
|
||||
content += par[1]
|
||||
content += "</p>\n"
|
||||
}
|
||||
return content
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
250
internal/frontend/qml/ProtonUI/DialogUpdate.qml
Normal file
250
internal/frontend/qml/ProtonUI/DialogUpdate.qml
Normal file
@ -0,0 +1,250 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// default options to make button accessible
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.2
|
||||
import ProtonUI 1.0
|
||||
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
|
||||
title: "Bridge update "+go.newversion
|
||||
|
||||
property alias introductionText : introduction.text
|
||||
property bool hasError : false
|
||||
|
||||
signal cancel()
|
||||
signal okay()
|
||||
|
||||
|
||||
isDialogBusy: currentIndex==1
|
||||
|
||||
Rectangle { // 0: Release notes and confirm
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
color: Style.transparent
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 5*Style.dialog.spacing
|
||||
|
||||
AccessibleText {
|
||||
id:introduction
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: Style.dialog.text
|
||||
linkColor: Style.dialog.textBlue
|
||||
font {
|
||||
pointSize: 0.8 * Style.dialog.fontSize * Style.pt
|
||||
}
|
||||
width: 2*root.width/3
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
// customize message per application
|
||||
text: ' <a href="%1">Release notes</a><br> New version %2<br> <br><br> <a href="%3">%3</a>'
|
||||
|
||||
onLinkActivated : {
|
||||
console.log("clicked link:", link)
|
||||
if (link == "releaseNotes"){
|
||||
root.hide()
|
||||
winMain.dialogVersionInfo.show()
|
||||
} else {
|
||||
root.hide()
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: introduction.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Style.dialog.spacing
|
||||
|
||||
ButtonRounded {
|
||||
fa_icon: Style.fa.times
|
||||
text: (go.goos=="linux" ? qsTr("Okay") : qsTr("Cancel"))
|
||||
color_main: Style.dialog.text
|
||||
onClicked: root.cancel()
|
||||
}
|
||||
|
||||
ButtonRounded {
|
||||
fa_icon: Style.fa.check
|
||||
text: qsTr("Update")
|
||||
visible: go.goos!="linux"
|
||||
color_main: Style.dialog.text
|
||||
color_minor: Style.main.textBlue
|
||||
isOpaque: true
|
||||
onClicked: root.okay()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { // 0: Check / download / unpack / prepare
|
||||
id: updateStatus
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
color: Style.transparent
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.dialog.spacing
|
||||
|
||||
AccessibleText {
|
||||
color: Style.dialog.text
|
||||
font {
|
||||
pointSize: Style.dialog.fontSize * Style.pt
|
||||
bold: false
|
||||
}
|
||||
width: 2*root.width/3
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
text: {
|
||||
switch (go.progressDescription) {
|
||||
case 1: return qsTr("Checking the current version.")
|
||||
case 2: return qsTr("Downloading the update files.")
|
||||
case 3: return qsTr("Verifying the update files.")
|
||||
case 4: return qsTr("Unpacking the update files.")
|
||||
case 5: return qsTr("Starting the update.")
|
||||
case 6: return qsTr("Quitting the application.")
|
||||
default: return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProgressBar {
|
||||
id: progressbar
|
||||
implicitWidth : 2*updateStatus.width/3
|
||||
implicitHeight : Style.exporting.rowHeight
|
||||
visible: go.progress!=0 // hack hide animation when clearing out progress bar
|
||||
value: go.progress
|
||||
property int current: go.total * go.progress
|
||||
property bool isFinished: finishedPartBar.width == progressbar.width
|
||||
background: Rectangle {
|
||||
radius : Style.exporting.boxRadius
|
||||
color : Style.exporting.progressBackground
|
||||
}
|
||||
contentItem: Item {
|
||||
Rectangle {
|
||||
id: finishedPartBar
|
||||
width : parent.width * progressbar.visualPosition
|
||||
height : parent.height
|
||||
radius : Style.exporting.boxRadius
|
||||
gradient : Gradient {
|
||||
GradientStop { position: 0.00; color: Qt.lighter(Style.main.textBlue,1.1) }
|
||||
GradientStop { position: 0.66; color: Style.main.textBlue }
|
||||
GradientStop { position: 1.00; color: Qt.darker(Style.main.textBlue,1.1) }
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation { duration:300; easing.type: Easing.InOutQuad }
|
||||
}
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: ""
|
||||
color: Style.main.background
|
||||
font {
|
||||
pointSize: Style.dialog.fontSize * Style.pt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { // 1: Something went wrong / All ok, closing bridge
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
color: Style.transparent
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 5*Style.dialog.spacing
|
||||
|
||||
AccessibleText {
|
||||
color: Style.dialog.text
|
||||
linkColor: Style.dialog.textBlue
|
||||
font {
|
||||
pointSize: Style.dialog.fontSize * Style.pt
|
||||
}
|
||||
width: 2*root.width/3
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
text: !root.hasError ? qsTr('Application will quit now to finish the update.', "message after successful update") :
|
||||
qsTr('<b>The update procedure was not successful!</b><br>Please follow the download link and update manually. <br><br><a href="%1">%1</a>').arg(go.downloadLink)
|
||||
|
||||
onLinkActivated : {
|
||||
console.log("clicked link:", link)
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
}
|
||||
|
||||
ButtonRounded{
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: root.hasError
|
||||
text: qsTr("Close")
|
||||
onClicked: root.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clear() {
|
||||
root.hasError = false
|
||||
go.progress = 0.0
|
||||
go.progressDescription = 0
|
||||
}
|
||||
|
||||
function finished(hasError) {
|
||||
root.hasError = hasError
|
||||
root.incrementCurrentIndex()
|
||||
}
|
||||
|
||||
onShow: {
|
||||
root.clear()
|
||||
}
|
||||
|
||||
onHide: {
|
||||
root.clear()
|
||||
}
|
||||
|
||||
onOkay: {
|
||||
switch (root.currentIndex) {
|
||||
case 0:
|
||||
go.startUpdate()
|
||||
}
|
||||
root.incrementCurrentIndex()
|
||||
}
|
||||
|
||||
onCancel: {
|
||||
root.hide()
|
||||
}
|
||||
}
|
||||
78
internal/frontend/qml/ProtonUI/FileAndFolderSelect.qml
Normal file
78
internal/frontend/qml/ProtonUI/FileAndFolderSelect.qml
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// one line input text field with label
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Dialogs 1.0
|
||||
import ProtonUI 1.0
|
||||
|
||||
Row {
|
||||
id: root
|
||||
spacing: Style.dialog.spacing
|
||||
|
||||
property string title : "title"
|
||||
|
||||
property alias path: inputPath.text
|
||||
property alias inputPath: inputPath
|
||||
property alias dialogVisible: pathDialog.visible
|
||||
|
||||
InputBox {
|
||||
id: inputPath
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
}
|
||||
spacing: Style.dialog.spacing
|
||||
field {
|
||||
height: browseButton.height
|
||||
width: root.width - root.spacing - browseButton.width
|
||||
}
|
||||
|
||||
label: title
|
||||
Component.onCompleted: sanitizePath(pathDialog.shortcuts.home)
|
||||
}
|
||||
|
||||
ButtonRounded {
|
||||
id: browseButton
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
}
|
||||
height: Style.dialog.heightInput
|
||||
color_main: Style.main.textBlue
|
||||
fa_icon: Style.fa.folder_open
|
||||
text: qsTr("Browse", "click to look through directory for a file or folder")
|
||||
onClicked: pathDialog.visible = true
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: pathDialog
|
||||
title: root.title + ":"
|
||||
folder: shortcuts.home
|
||||
onAccepted: sanitizePath(pathDialog.fileUrl.toString())
|
||||
selectFolder: true
|
||||
}
|
||||
|
||||
function sanitizePath(path) {
|
||||
var pattern = "file://"
|
||||
if (go.goos=="windows") pattern+="/"
|
||||
inputPath.text = path.replace(pattern, "")
|
||||
}
|
||||
|
||||
function checkNonEmpty() {
|
||||
return inputPath.text != ""
|
||||
}
|
||||
}
|
||||
101
internal/frontend/qml/ProtonUI/InfoToolTip.qml
Normal file
101
internal/frontend/qml/ProtonUI/InfoToolTip.qml
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// on hover information
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.2
|
||||
import ProtonUI 1.0
|
||||
|
||||
Text { // info icon
|
||||
id:root
|
||||
property alias info : tip.text
|
||||
font {
|
||||
family: Style.fontawesome.name
|
||||
pointSize : Style.dialog.iconSize * Style.pt
|
||||
}
|
||||
text: Style.fa.info_circle
|
||||
color: Style.main.textDisabled
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onEntered : tip.visible=true
|
||||
onExited : tip.visible=false
|
||||
}
|
||||
|
||||
ToolTip {
|
||||
id: tip
|
||||
width: Style.bubble.width
|
||||
x: - 0.2*tip.width
|
||||
y: - tip.height
|
||||
|
||||
topPadding : Style.main.fontSize/2
|
||||
bottomPadding : Style.main.fontSize/2
|
||||
leftPadding : Style.bubble.widthPane + Style.dialog.spacing
|
||||
rightPadding: Style.dialog.spacing
|
||||
delay: 800
|
||||
|
||||
background : Rectangle {
|
||||
id: bck
|
||||
color: Style.bubble.paneBackground
|
||||
radius : Style.bubble.radius
|
||||
|
||||
|
||||
Text {
|
||||
id: icon
|
||||
color: Style.bubble.background
|
||||
text: Style.fa.info_circle
|
||||
font {
|
||||
family : Style.fontawesome.name
|
||||
pointSize : Style.dialog.iconSize * Style.pt
|
||||
}
|
||||
anchors {
|
||||
verticalCenter : bck.verticalCenter
|
||||
left : bck.left
|
||||
leftMargin : (Style.bubble.widthPane - icon.width) / 2
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { // right edge
|
||||
anchors {
|
||||
fill : bck
|
||||
leftMargin : Style.bubble.widthPane
|
||||
}
|
||||
radius: parent.radius
|
||||
color: Style.bubble.background
|
||||
}
|
||||
|
||||
Rectangle { // center background
|
||||
anchors {
|
||||
fill : parent
|
||||
leftMargin : Style.bubble.widthPane
|
||||
rightMargin : Style.bubble.widthPane
|
||||
}
|
||||
color: Style.bubble.background
|
||||
}
|
||||
}
|
||||
|
||||
contentItem : Text {
|
||||
text: tip.text
|
||||
color: Style.bubble.text
|
||||
wrapMode: Text.Wrap
|
||||
font.pointSize: Style.main.fontSize * Style.pt
|
||||
}
|
||||
}
|
||||
}
|
||||
233
internal/frontend/qml/ProtonUI/InformationBar.qml
Normal file
233
internal/frontend/qml/ProtonUI/InformationBar.qml
Normal file
@ -0,0 +1,233 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Important information under title bar
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls 2.1
|
||||
import ProtonUI 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
property var iTry: 0
|
||||
property var secLeft: 0
|
||||
property var second: 1000 // convert millisecond to second
|
||||
property var checkInterval: [ 5, 10, 30, 60, 120, 300, 600 ] // seconds
|
||||
property bool isVisible: true
|
||||
property var fontSize : 1.2 * Style.main.fontSize
|
||||
color : "black"
|
||||
state: "upToDate"
|
||||
|
||||
Timer {
|
||||
id: retryInternet
|
||||
interval: second
|
||||
triggeredOnStart: false
|
||||
repeat: true
|
||||
onTriggered : {
|
||||
secLeft--
|
||||
if (secLeft <= 0) {
|
||||
retryInternet.stop()
|
||||
go.checkInternet()
|
||||
if (iTry < checkInterval.length-1) {
|
||||
iTry++
|
||||
}
|
||||
secLeft=checkInterval[iTry]
|
||||
retryInternet.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.centerIn: root
|
||||
visible: root.isVisible
|
||||
spacing: Style.main.leftMarginButton
|
||||
|
||||
AccessibleText {
|
||||
id: message
|
||||
font.pointSize: root.fontSize * Style.pt
|
||||
}
|
||||
|
||||
ClickIconText {
|
||||
anchors.verticalCenter : message.verticalCenter
|
||||
text : "("+go.newversion+" " + qsTr("release notes", "display the release notes from the new version")+")"
|
||||
visible : root.state=="oldVersion" && ( go.changelog!="" || go.bugfixes!="")
|
||||
iconText : ""
|
||||
onClicked : {
|
||||
dialogVersionInfo.show()
|
||||
}
|
||||
fontSize : root.fontSize
|
||||
}
|
||||
|
||||
ClickIconText {
|
||||
anchors.verticalCenter : message.verticalCenter
|
||||
text : root.state=="oldVersion" || root.state == "forceUpdate" ?
|
||||
qsTr("Update", "click to update to a new version when one is available") :
|
||||
qsTr("Retry now", "click to try to connect to the internet when the app is disconnected from the internet")
|
||||
visible : root.state!="internetCheck"
|
||||
iconText : ""
|
||||
onClicked : {
|
||||
if (root.state=="oldVersion" || root.state=="forceUpdate" ) {
|
||||
winMain.dialogUpdate.show()
|
||||
} else {
|
||||
go.checkInternet()
|
||||
}
|
||||
}
|
||||
fontSize : root.fontSize
|
||||
textUnderline: true
|
||||
}
|
||||
Text {
|
||||
anchors.baseline : message.baseline
|
||||
color: Style.main.text
|
||||
font {
|
||||
pointSize : root.fontSize * Style.pt
|
||||
bold : true
|
||||
}
|
||||
visible: root.state=="oldVersion" || root.state=="noInternet"
|
||||
text : "|"
|
||||
}
|
||||
ClickIconText {
|
||||
anchors.verticalCenter : message.verticalCenter
|
||||
iconText : ""
|
||||
text : root.state == "noInternet" ?
|
||||
qsTr("Troubleshoot", "Show modal screen with additional tips for troubleshooting connection issues") :
|
||||
qsTr("Remind me later", "Do not install new version and dismiss a notification")
|
||||
visible : root.state=="oldVersion" || root.state=="noInternet"
|
||||
onClicked : {
|
||||
if (root.state == "oldVersion") {
|
||||
root.state = "upToDate"
|
||||
}
|
||||
if (root.state == "noInternet") {
|
||||
dialogConnectionTroubleshoot.show()
|
||||
}
|
||||
}
|
||||
fontSize : root.fontSize
|
||||
textUnderline: true
|
||||
}
|
||||
}
|
||||
|
||||
onStateChanged : {
|
||||
switch (root.state) {
|
||||
case "forceUpdate" :
|
||||
gui.warningFlags |= Style.errorInfoBar
|
||||
break;
|
||||
case "upToDate" :
|
||||
gui.warningFlags &= ~Style.warnInfoBar
|
||||
iTry = 0
|
||||
secLeft=checkInterval[iTry]
|
||||
break;
|
||||
case "noInternet" :
|
||||
gui.warningFlags |= Style.warnInfoBar
|
||||
retryInternet.start()
|
||||
secLeft=checkInterval[iTry]
|
||||
break;
|
||||
default :
|
||||
gui.warningFlags |= Style.warnInfoBar
|
||||
}
|
||||
|
||||
if (root.state!="noInternet") {
|
||||
retryInternet.stop()
|
||||
}
|
||||
}
|
||||
|
||||
function timeToRetry() {
|
||||
if (secLeft==1){
|
||||
return qsTr("a second", "time to wait till internet connection is retried")
|
||||
} else if (secLeft<60){
|
||||
return secLeft + " " + qsTr("seconds", "time to wait till internet connection is retried")
|
||||
} else {
|
||||
var leading = ""+secLeft%60
|
||||
if (leading.length < 2) {
|
||||
leading = "0" + leading
|
||||
}
|
||||
return Math.floor(secLeft/60) + ":" + leading
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "internetCheck"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
height: 2* Style.main.fontSize
|
||||
isVisible: true
|
||||
color: Style.main.textOrange
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
color: Style.main.background
|
||||
text: qsTr("Checking connection. Please wait...", "displayed after user retries internet connection")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "noInternet"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
height: 2* Style.main.fontSize
|
||||
isVisible: true
|
||||
color: Style.main.textRed
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
color: Style.main.line
|
||||
text: qsTr("Cannot contact server. Retrying in ", "displayed when the app is disconnected from the internet or server has problems")+timeToRetry()+"."
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "oldVersion"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
height: 2* Style.main.fontSize
|
||||
isVisible: true
|
||||
color: Style.main.textBlue
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
color: Style.main.background
|
||||
text: qsTr("An update is available.", "displayed in a notification when an app update is available")
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "forceUpdate"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
height: 2* Style.main.fontSize
|
||||
isVisible: true
|
||||
color: Style.main.textRed
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
color: Style.main.line
|
||||
text: qsTr("%1 is outdated.", "displayed in a notification when app is outdated").arg(go.programTitle)
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "upToDate"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
height: 0
|
||||
isVisible: false
|
||||
color: Style.main.textBlue
|
||||
}
|
||||
PropertyChanges {
|
||||
target: message
|
||||
color: Style.main.background
|
||||
text: ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
78
internal/frontend/qml/ProtonUI/InputBox.qml
Normal file
78
internal/frontend/qml/ProtonUI/InputBox.qml
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// one line input text field with label
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import ProtonUI 1.0
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
Column {
|
||||
id: root
|
||||
property alias label: textlabel.text
|
||||
property alias placeholderText: inputField.placeholderText
|
||||
property alias echoMode: inputField.echoMode
|
||||
property alias text: inputField.text
|
||||
property alias field: inputField
|
||||
|
||||
signal accepted()
|
||||
|
||||
spacing: Style.dialog.heightSeparator
|
||||
|
||||
Text {
|
||||
id: textlabel
|
||||
font {
|
||||
pointSize: Style.dialog.fontSize * Style.pt
|
||||
bold: true
|
||||
}
|
||||
color: Style.dialog.text
|
||||
}
|
||||
|
||||
|
||||
TextField {
|
||||
id: inputField
|
||||
width: Style.dialog.widthInput
|
||||
height: Style.dialog.heightButton
|
||||
selectByMouse : true
|
||||
selectionColor : Style.main.textBlue
|
||||
padding : Style.dialog.radiusButton
|
||||
color : Style.dialog.text
|
||||
font {
|
||||
pointSize : Style.dialog.fontSize * Style.pt
|
||||
family : Style.fontawesome.name
|
||||
}
|
||||
background: Rectangle {
|
||||
color : Style.dialog.background
|
||||
radius: Style.dialog.radiusButton
|
||||
border {
|
||||
color : Style.dialog.line
|
||||
width : Style.dialog.borderInput
|
||||
}
|
||||
layer.enabled: true
|
||||
layer.effect: FastBlur {
|
||||
anchors.fill: parent
|
||||
radius: 8 * Style.px
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target : inputField
|
||||
onAccepted : root.accepted()
|
||||
}
|
||||
}
|
||||
172
internal/frontend/qml/ProtonUI/InputField.qml
Normal file
172
internal/frontend/qml/ProtonUI/InputField.qml
Normal file
@ -0,0 +1,172 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// one line input text field with label
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.1
|
||||
import ProtonUI 1.0
|
||||
|
||||
Column {
|
||||
id: root
|
||||
property alias focusInput : inputField.focus
|
||||
property alias label : textlabel.text
|
||||
property alias iconText : iconInput.text
|
||||
property alias placeholderText : inputField.placeholderText
|
||||
property alias text : inputField.text
|
||||
property bool isPassword : false
|
||||
property string rightIcon : ""
|
||||
|
||||
signal accepted()
|
||||
signal editingFinished()
|
||||
|
||||
spacing: Style.dialog.heightSeparator
|
||||
anchors.horizontalCenter : parent.horizontalCenter
|
||||
|
||||
AccessibleText {
|
||||
id: textlabel
|
||||
anchors.left : parent.left
|
||||
font {
|
||||
pointSize : Style.dialog.fontSize * Style.pt
|
||||
bold : true
|
||||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
color : Style.dialog.text
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: inputWrap
|
||||
anchors.horizontalCenter : parent.horizontalCenter
|
||||
width : Style.dialog.widthInput
|
||||
height : Style.dialog.heightInput
|
||||
color : "transparent"
|
||||
|
||||
Text {
|
||||
id: iconInput
|
||||
anchors {
|
||||
top : parent.top
|
||||
left : parent.left
|
||||
}
|
||||
color : Style.dialog.text
|
||||
font {
|
||||
pointSize : Style.dialog.iconSize * Style.pt
|
||||
family : Style.fontawesome.name
|
||||
}
|
||||
text: "o"
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: inputField
|
||||
anchors {
|
||||
fill: inputWrap
|
||||
leftMargin : Style.dialog.iconSize+Style.dialog.fontSize
|
||||
bottomMargin : inputWrap.height - Style.dialog.iconSize
|
||||
}
|
||||
verticalAlignment : TextInput.AlignTop
|
||||
horizontalAlignment : TextInput.AlignLeft
|
||||
selectByMouse : true
|
||||
color : Style.dialog.text
|
||||
selectionColor : Style.main.textBlue
|
||||
font {
|
||||
pointSize : Style.dialog.fontSize * Style.pt
|
||||
family : Style.fontawesome.name
|
||||
}
|
||||
padding: 0
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color : "transparent"
|
||||
}
|
||||
Component.onCompleted : {
|
||||
if (isPassword) {
|
||||
echoMode = TextInput.Password
|
||||
} else {
|
||||
echoMode = TextInput.Normal
|
||||
}
|
||||
}
|
||||
|
||||
Accessible.name: textlabel.text
|
||||
Accessible.description: textlabel.text
|
||||
}
|
||||
|
||||
Text {
|
||||
id: iconRight
|
||||
anchors {
|
||||
top : parent.top
|
||||
right : parent.right
|
||||
}
|
||||
color : Style.dialog.text
|
||||
font {
|
||||
pointSize : Style.dialog.iconSize * Style.pt
|
||||
family : Style.fontawesome.name
|
||||
}
|
||||
text: ( !isPassword ? "" : (
|
||||
inputField.echoMode == TextInput.Password ? Style.fa.eye : Style.fa.eye_slash
|
||||
)) + " " + rightIcon
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if (isPassword) {
|
||||
if (inputField.echoMode == TextInput.Password) inputField.echoMode = TextInput.Normal
|
||||
else inputField.echoMode = TextInput.Password
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
bottom : parent.bottom
|
||||
}
|
||||
height: Math.max(Style.main.border,1)
|
||||
color: Style.dialog.text
|
||||
}
|
||||
}
|
||||
|
||||
function checkNonEmpty() {
|
||||
if (inputField.text == "") {
|
||||
rightIcon = Style.fa.exclamation_triangle
|
||||
root.placeholderText = ""
|
||||
inputField.focus = true
|
||||
return false
|
||||
} else {
|
||||
rightIcon = Style.fa.check_circle
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function hidePasswordText() {
|
||||
if (root.isPassword) inputField.echoMode = TextInput.Password
|
||||
}
|
||||
|
||||
function forceFocus() {
|
||||
inputField.forceActiveFocus()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: inputField
|
||||
onAccepted: root.accepted()
|
||||
onEditingFinished: root.editingFinished()
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
if (event.key == Qt.Key_Enter) {
|
||||
root.accepted()
|
||||
}
|
||||
}
|
||||
}
|
||||
79
internal/frontend/qml/ProtonUI/InstanceExistsWindow.qml
Normal file
79
internal/frontend/qml/ProtonUI/InstanceExistsWindow.qml
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// This is main window
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Window 2.2
|
||||
import ProtonUI 1.0
|
||||
|
||||
|
||||
// Main Window
|
||||
Window {
|
||||
id:winMain
|
||||
|
||||
// main window appeareance
|
||||
width : Style.main.width
|
||||
height : Style.main.height
|
||||
flags : Qt.Window | Qt.Dialog
|
||||
title: qsTr("ProtonMail Bridge", "app title")
|
||||
color : Style.main.background
|
||||
visible : true
|
||||
|
||||
Text {
|
||||
id: title
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.top
|
||||
topMargin: Style.main.topMargin
|
||||
}
|
||||
font{
|
||||
pointSize: Style.dialog.titleSize * Style.pt
|
||||
}
|
||||
color: Style.main.text
|
||||
text:
|
||||
"<span style='font-family: " + Style.fontawesome.name + "'>" + Style.fa.exclamation_triangle + "</span> " +
|
||||
qsTr ("Warning: Instance exists", "displayed when a version of the app is opened while another is already running")
|
||||
}
|
||||
|
||||
Text {
|
||||
id: message
|
||||
anchors.centerIn : parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pointSize: Style.dialog.fontSize * Style.pt
|
||||
color: Style.main.text
|
||||
width: 2*parent.width/3
|
||||
wrapMode: Text.Wrap
|
||||
text: qsTr("An instance of the ProtonMail Bridge is already running.", "displayed when a version of the app is opened while another is already running") + " " +
|
||||
qsTr("Please close the existing ProtonMail Bridge process before starting a new one.", "displayed when a version of the app is opened while another is already running")+ " " +
|
||||
qsTr("This program will close now.", "displayed when a version of the app is opened while another is already running")
|
||||
}
|
||||
|
||||
ButtonRounded {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
bottom: parent.bottom
|
||||
bottomMargin: Style.main.bottomMargin
|
||||
}
|
||||
text: qsTr("Okay", "confirms and dismisses a notification")
|
||||
color_main: Style.dialog.text
|
||||
color_minor: Style.main.textBlue
|
||||
isOpaque: true
|
||||
onClicked: Qt.quit()
|
||||
}
|
||||
}
|
||||
|
||||
150
internal/frontend/qml/ProtonUI/LogoHeader.qml
Normal file
150
internal/frontend/qml/ProtonUI/LogoHeader.qml
Normal file
@ -0,0 +1,150 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Header of window with logo and buttons
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
import QtQuick.Window 2.2
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
// dimensions
|
||||
property Window parentWin
|
||||
property string title: "ProtonMail Bridge"
|
||||
property bool hasIcon : true
|
||||
anchors.top : parent.top
|
||||
anchors.right : parent.right
|
||||
width : Style.main.width
|
||||
height : Style.title.height
|
||||
// style
|
||||
color : Style.title.background
|
||||
|
||||
signal hideClicked()
|
||||
|
||||
// Drag to move : https://stackoverflow.com/a/18927884
|
||||
MouseArea {
|
||||
property variant clickPos: "1,1"
|
||||
anchors.fill: parent
|
||||
onPressed: {
|
||||
clickPos = Qt.point(mouse.x,mouse.y)
|
||||
}
|
||||
onPositionChanged: {
|
||||
var delta = Qt.point(mouse.x-clickPos.x, mouse.y-clickPos.y)
|
||||
parentWin.x += delta.x;
|
||||
parentWin.y += delta.y;
|
||||
}
|
||||
}
|
||||
|
||||
// logo
|
||||
Image {
|
||||
id: imgLogo
|
||||
height : Style.title.imgHeight
|
||||
fillMode : Image.PreserveAspectFit
|
||||
visible: root.hasIcon
|
||||
anchors {
|
||||
left : root.left
|
||||
leftMargin : Style.title.leftMargin
|
||||
verticalCenter : root.verticalCenter
|
||||
}
|
||||
//source : "qrc://logo.svg"
|
||||
source : "logo.svg"
|
||||
smooth : true
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: titleMetrics
|
||||
elideWidth: 2*root.width/3
|
||||
elide: Qt.ElideMiddle
|
||||
font: titleText.font
|
||||
text: root.title
|
||||
}
|
||||
|
||||
// Title
|
||||
Text {
|
||||
id: titleText
|
||||
anchors {
|
||||
left : hasIcon ? imgLogo.right : parent.left
|
||||
leftMargin : hasIcon ? Style.title.leftMargin : Style.main.leftMargin
|
||||
verticalCenter : root.verticalCenter
|
||||
}
|
||||
text : titleMetrics.elidedText
|
||||
color : Style.title.text
|
||||
font.pointSize : Style.title.fontSize * Style.pt
|
||||
}
|
||||
|
||||
// Underline Button
|
||||
Rectangle {
|
||||
id: buttonUndrLine
|
||||
anchors {
|
||||
verticalCenter : root.verticalCenter
|
||||
right : buttonCross.left
|
||||
rightMargin : 2*Style.title.fontSize
|
||||
}
|
||||
width : Style.title.fontSize
|
||||
height : Style.title.fontSize
|
||||
color : "transparent"
|
||||
Canvas {
|
||||
anchors.fill: parent
|
||||
onPaint: {
|
||||
var val = Style.title.fontSize
|
||||
var ctx = getContext("2d")
|
||||
ctx.strokeStyle = 'white'
|
||||
ctx.strokeWidth = 4
|
||||
ctx.moveTo(0 , val-1)
|
||||
ctx.lineTo(val, val-1)
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.hideClicked()
|
||||
}
|
||||
}
|
||||
|
||||
// Cross Button
|
||||
Rectangle {
|
||||
id: buttonCross
|
||||
anchors {
|
||||
verticalCenter : root.verticalCenter
|
||||
right : root.right
|
||||
rightMargin : Style.main.rightMargin
|
||||
}
|
||||
width : Style.title.fontSize
|
||||
height : Style.title.fontSize
|
||||
color : "transparent"
|
||||
Canvas {
|
||||
anchors.fill: parent
|
||||
onPaint: {
|
||||
var val = Style.title.fontSize
|
||||
var ctx = getContext("2d")
|
||||
ctx.strokeStyle = 'white'
|
||||
ctx.strokeWidth = 4
|
||||
ctx.moveTo(0,0)
|
||||
ctx.lineTo(val,val)
|
||||
ctx.moveTo(val,0)
|
||||
ctx.lineTo(0,val)
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.hideClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
81
internal/frontend/qml/ProtonUI/PopupMessage.qml
Normal file
81
internal/frontend/qml/ProtonUI/PopupMessage.qml
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Popup message
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.2
|
||||
import ProtonUI 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
color: Style.transparent
|
||||
property alias text: message.text
|
||||
visible: false
|
||||
|
||||
MouseArea { // prevent action below
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: backgroundInp
|
||||
anchors.centerIn : root
|
||||
color : Style.errorDialog.background
|
||||
radius : Style.errorDialog.radius
|
||||
width : parent.width/3.
|
||||
height : contentInp.height
|
||||
|
||||
Column {
|
||||
id: contentInp
|
||||
anchors.horizontalCenter: backgroundInp.horizontalCenter
|
||||
spacing: Style.dialog.heightSeparator
|
||||
topPadding: Style.dialog.heightSeparator
|
||||
bottomPadding: Style.dialog.heightSeparator
|
||||
|
||||
AccessibleText {
|
||||
id: message
|
||||
font {
|
||||
pointSize : Style.errorDialog.fontSize * Style.pt
|
||||
bold : true
|
||||
}
|
||||
color: Style.errorDialog.text
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
width : backgroundInp.width - 2*Style.main.rightMargin
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
ButtonRounded {
|
||||
text : qsTr("Okay", "todo")
|
||||
isOpaque : true
|
||||
color_main : Style.dialog.background
|
||||
color_minor : Style.dialog.textBlue
|
||||
onClicked : root.hide()
|
||||
anchors.horizontalCenter : parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function show(text) {
|
||||
root.text = text
|
||||
root.visible = true
|
||||
}
|
||||
|
||||
function hide() {
|
||||
root.state = "Okay"
|
||||
root.visible=false
|
||||
}
|
||||
}
|
||||
16
internal/frontend/qml/ProtonUI/ProgressBar.qml
Normal file
16
internal/frontend/qml/ProtonUI/ProgressBar.qml
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
1089
internal/frontend/qml/ProtonUI/Style.qml
Normal file
1089
internal/frontend/qml/ProtonUI/Style.qml
Normal file
File diff suppressed because it is too large
Load Diff
69
internal/frontend/qml/ProtonUI/TLSCertPinIssueBar.qml
Normal file
69
internal/frontend/qml/ProtonUI/TLSCertPinIssueBar.qml
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Important information under title bar
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls 2.1
|
||||
import ProtonUI 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
height: 0
|
||||
visible: state != "ok"
|
||||
state: "ok"
|
||||
color: "black"
|
||||
property var fontSize : 1.0 * Style.main.fontSize
|
||||
|
||||
Row {
|
||||
anchors.centerIn: root
|
||||
visible: root.visible
|
||||
spacing: Style.main.leftMarginButton
|
||||
|
||||
AccessibleText {
|
||||
id: message
|
||||
font.pointSize: root.fontSize * Style.pt
|
||||
|
||||
text: qsTr("Connection security error: Your network connection to Proton services may be insecure.", "message in bar showed when TLS Pinning fails")
|
||||
}
|
||||
|
||||
ClickIconText {
|
||||
anchors.verticalCenter : message.verticalCenter
|
||||
iconText : ""
|
||||
text : qsTr("Learn more", "This button opens TLS Pinning issue modal with more explanation")
|
||||
visible : root.visible
|
||||
onClicked : {
|
||||
winMain.dialogTlsCert.show()
|
||||
}
|
||||
fontSize : root.fontSize
|
||||
textUnderline: true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "notOK"
|
||||
PropertyChanges {
|
||||
target: root
|
||||
height: 2* Style.main.fontSize
|
||||
color: Style.main.textRed
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
103
internal/frontend/qml/ProtonUI/TabButton.qml
Normal file
103
internal/frontend/qml/ProtonUI/TabButton.qml
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Button with text and icon for tabbar
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
import QtQuick.Controls 2.1
|
||||
|
||||
AccessibleButton {
|
||||
id: root
|
||||
property alias iconText : icon.text
|
||||
property alias title : titleText.text
|
||||
property color textColor : {
|
||||
if (root.state=="deactivated") {
|
||||
return Qt.lighter(Style.tabbar.textInactive, root.hovered || root.activeFocus ? 1.25 : 1.0)
|
||||
}
|
||||
if (root.state=="activated") {
|
||||
return Style.tabbar.text
|
||||
}
|
||||
}
|
||||
|
||||
text: root.title
|
||||
Accessible.description: root.title + " tab"
|
||||
|
||||
width : titleMetrics.width // Style.tabbar.widthButton
|
||||
height : Style.tabbar.heightButton
|
||||
padding: 0
|
||||
|
||||
background: Rectangle {
|
||||
color : Style.transparent
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
}
|
||||
|
||||
contentItem : Rectangle {
|
||||
color: "transparent"
|
||||
scale : root.pressed ? 0.96 : 1.00
|
||||
|
||||
Text {
|
||||
id: icon
|
||||
// dimenstions
|
||||
anchors {
|
||||
top : parent.top
|
||||
horizontalCenter : parent.horizontalCenter
|
||||
}
|
||||
// style
|
||||
color : root.textColor
|
||||
font {
|
||||
family : Style.fontawesome.name
|
||||
pointSize : Style.tabbar.iconSize * Style.pt
|
||||
}
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: titleMetrics
|
||||
text : root.title
|
||||
font.pointSize : titleText.font.pointSize
|
||||
}
|
||||
|
||||
Text {
|
||||
id: titleText
|
||||
// dimenstions
|
||||
anchors {
|
||||
bottom : parent.bottom
|
||||
horizontalCenter : parent.horizontalCenter
|
||||
}
|
||||
// style
|
||||
color : root.textColor
|
||||
font {
|
||||
pointSize : Style.tabbar.fontSize * Style.pt
|
||||
bold : root.state=="activated"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "activated"
|
||||
},
|
||||
State {
|
||||
name: "deactivated"
|
||||
}
|
||||
]
|
||||
}
|
||||
107
internal/frontend/qml/ProtonUI/TabLabels.qml
Normal file
107
internal/frontend/qml/ProtonUI/TabLabels.qml
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// Tab labels
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
// attributes
|
||||
property alias model : tablist.model
|
||||
property alias currentIndex : tablist.currentIndex
|
||||
property int spacing : Style.tabbar.widthButton + Style.tabbar.spacingButton
|
||||
currentIndex: 0
|
||||
|
||||
// appereance
|
||||
height : Style.tabbar.height
|
||||
color : Style.tabbar.background
|
||||
|
||||
// content
|
||||
ListView {
|
||||
id: tablist
|
||||
// dimensions
|
||||
anchors {
|
||||
fill: root
|
||||
leftMargin : Style.tabbar.leftMargin
|
||||
rightMargin : Style.main.rightMargin
|
||||
bottomMargin : Style.tabbar.bottomMargin
|
||||
}
|
||||
spacing: Style.tabbar.spacingButton
|
||||
interactive : false
|
||||
// style
|
||||
orientation: Qt.Horizontal
|
||||
delegate: TabButton {
|
||||
anchors.bottom : parent.bottom
|
||||
title : modelData.title
|
||||
iconText : modelData.iconText
|
||||
state : index == tablist.currentIndex ? "activated" : "deactivated"
|
||||
onClicked : {
|
||||
tablist.currentIndex = index
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Quit button
|
||||
TabButton {
|
||||
id: buttonQuit
|
||||
title : qsTr("Close Bridge", "quits the application")
|
||||
iconText : Style.fa.power_off
|
||||
state : "deactivated"
|
||||
visible : Style.tabbar.rightButton=="quit"
|
||||
anchors {
|
||||
right : root.right
|
||||
bottom : root.bottom
|
||||
rightMargin : Style.main.rightMargin
|
||||
bottomMargin : Style.tabbar.bottomMargin
|
||||
}
|
||||
|
||||
Accessible.description: buttonQuit.title
|
||||
|
||||
onClicked : {
|
||||
dialogGlobal.state = "quit"
|
||||
dialogGlobal.show()
|
||||
}
|
||||
}
|
||||
|
||||
// Add account
|
||||
TabButton {
|
||||
id: buttonAddAccount
|
||||
title : qsTr("Add account", "start the authentication to add account")
|
||||
iconText : Style.fa.plus_circle
|
||||
state : "deactivated"
|
||||
visible : Style.tabbar.rightButton=="add account"
|
||||
anchors {
|
||||
right : root.right
|
||||
bottom : root.bottom
|
||||
rightMargin : Style.main.rightMargin
|
||||
bottomMargin : Style.tabbar.bottomMargin
|
||||
}
|
||||
|
||||
Accessible.description: buttonAddAccount.title
|
||||
|
||||
onClicked : dialogAddUser.show()
|
||||
}
|
||||
|
||||
function focusButton() {
|
||||
tablist.currentItem.forceActiveFocus()
|
||||
tablist.currentItem.Accessible.focusedChanged(true)
|
||||
}
|
||||
}
|
||||
|
||||
45
internal/frontend/qml/ProtonUI/TextLabel.qml
Normal file
45
internal/frontend/qml/ProtonUI/TextLabel.qml
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
|
||||
AccessibleText{
|
||||
id: root
|
||||
property bool hasCopyButton : false
|
||||
font.pointSize: Style.main.fontSize * Style.pt
|
||||
state: "label"
|
||||
|
||||
states : [
|
||||
State {
|
||||
name: "label"
|
||||
PropertyChanges {
|
||||
target : root
|
||||
font.bold : false
|
||||
color : Style.main.textDisabled
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "heading"
|
||||
PropertyChanges {
|
||||
target : root
|
||||
font.bold : true
|
||||
color : Style.main.textDisabled
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
85
internal/frontend/qml/ProtonUI/TextValue.qml
Normal file
85
internal/frontend/qml/ProtonUI/TextValue.qml
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import QtQuick 2.8
|
||||
import ProtonUI 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
property string text: "undef"
|
||||
width: copyIcon.width + valueText.width
|
||||
height: Math.max(copyIcon.height, valueText.contentHeight)
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
id: copyIcon
|
||||
width: Style.info.leftMarginIcon*2 + Style.info.iconSize
|
||||
height : Style.info.iconSize
|
||||
color: "transparent"
|
||||
anchors {
|
||||
top: root.top
|
||||
left: root.left
|
||||
}
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
font {
|
||||
pointSize : Style.info.iconSize * Style.pt
|
||||
family : Style.fontawesome.name
|
||||
}
|
||||
color : Style.main.textInactive
|
||||
text: Style.fa.copy
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked : {
|
||||
valueText.select(0, valueText.length)
|
||||
valueText.copy()
|
||||
valueText.deselect()
|
||||
}
|
||||
onPressed: copyIcon.scale = 0.90
|
||||
onReleased: copyIcon.scale = 1
|
||||
}
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: qsTr("Copy %1 to clipboard", "Click to copy the value to system clipboard.").arg(root.text)
|
||||
Accessible.description: Accessible.name
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
id: valueText
|
||||
width: Style.info.widthValue
|
||||
height: Style.main.fontSize
|
||||
anchors {
|
||||
top: root.top
|
||||
left: copyIcon.right
|
||||
}
|
||||
font {
|
||||
pointSize: Style.main.fontSize * Style.pt
|
||||
}
|
||||
color: Style.main.text
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
selectByKeyboard: true
|
||||
wrapMode: TextEdit.Wrap
|
||||
text: root.text
|
||||
selectionColor: Style.dialog.textBlue
|
||||
|
||||
Accessible.role: Accessible.StaticText
|
||||
Accessible.name: root.text
|
||||
Accessible.description: Accessible.name
|
||||
}
|
||||
}
|
||||
348
internal/frontend/qml/ProtonUI/WindowTitleBar.qml
Normal file
348
internal/frontend/qml/ProtonUI/WindowTitleBar.qml
Normal file
@ -0,0 +1,348 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
// simulating window title bar with different color
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Window 2.2
|
||||
import ProtonUI 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
height: root.isDarwin ? Style.titleMacOS.height : Style.title.height
|
||||
color: "transparent"
|
||||
property bool isDarwin : (go.goos == "darwin")
|
||||
property QtObject window
|
||||
anchors {
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
top : parent.top
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
property point diff: "0,0"
|
||||
anchors {
|
||||
top: root.top
|
||||
bottom: root.bottom
|
||||
left: root.left
|
||||
right: root.isDarwin ? root.right : iconRowWin.left
|
||||
}
|
||||
onPressed: {
|
||||
diff = Qt.point(window.x, window.y)
|
||||
var mousePos = mapToGlobal(mouse.x, mouse.y)
|
||||
diff.x -= mousePos.x
|
||||
diff.y -= mousePos.y
|
||||
}
|
||||
onPositionChanged: {
|
||||
var currPos = mapToGlobal(mouse.x, mouse.y)
|
||||
window.x = currPos.x + diff.x
|
||||
window.y = currPos.y + diff.y
|
||||
}
|
||||
}
|
||||
|
||||
// top background
|
||||
Rectangle {
|
||||
id: upperBackground
|
||||
anchors.fill: root
|
||||
color: (isDarwin? Style.titleMacOS.background : Style.title.background )
|
||||
radius: (isDarwin? Style.titleMacOS.radius : 0)
|
||||
border {
|
||||
width: Style.main.border
|
||||
color: Style.title.background
|
||||
}
|
||||
}
|
||||
// bottom background
|
||||
Rectangle {
|
||||
id: lowerBorder
|
||||
anchors {
|
||||
top: root.verticalCenter
|
||||
left: root.left
|
||||
right: root.right
|
||||
bottom: root.bottom
|
||||
}
|
||||
color: Style.title.background
|
||||
Rectangle {
|
||||
id: lowerBackground
|
||||
anchors{
|
||||
fill : parent
|
||||
leftMargin : Style.main.border
|
||||
rightMargin : Style.main.border
|
||||
}
|
||||
color: upperBackground.color
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Title
|
||||
TextMetrics {
|
||||
id: titleMetrics
|
||||
text : window.title
|
||||
font : isDarwin ? titleMac.font : titleWin.font
|
||||
elide: Qt.ElideMiddle
|
||||
elideWidth : window.width/2
|
||||
}
|
||||
Text {
|
||||
id: titleWin
|
||||
visible: !isDarwin
|
||||
anchors {
|
||||
baseline : logo.bottom
|
||||
left : logo.right
|
||||
leftMargin : Style.title.leftMargin/1.5
|
||||
}
|
||||
color : window.active ? Style.title.text : Style.main.textDisabled
|
||||
text : titleMetrics.elidedText
|
||||
font.pointSize : Style.main.fontSize * Style.pt
|
||||
}
|
||||
Text {
|
||||
id: titleMac
|
||||
visible: isDarwin
|
||||
anchors {
|
||||
verticalCenter : parent.verticalCenter
|
||||
left : parent.left
|
||||
leftMargin : (parent.width-width)/2
|
||||
}
|
||||
color : window.active ? Style.title.text : Style.main.textDisabled
|
||||
text : titleMetrics.elidedText
|
||||
font.pointSize : Style.main.fontSize * Style.pt
|
||||
}
|
||||
|
||||
|
||||
// MACOS
|
||||
MouseArea {
|
||||
anchors.fill: iconRowMac
|
||||
property string beforeHover
|
||||
hoverEnabled: true
|
||||
onEntered: {
|
||||
beforeHover=iconRed.state
|
||||
//iconYellow.state="hover"
|
||||
iconRed.state="hover"
|
||||
}
|
||||
onExited: {
|
||||
//iconYellow.state=beforeHover
|
||||
iconRed.state=beforeHover
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: window
|
||||
onActiveChanged : {
|
||||
if (window.active) {
|
||||
//iconYellow.state="normal"
|
||||
iconRed.state="normal"
|
||||
} else {
|
||||
//iconYellow.state="disabled"
|
||||
iconRed.state="disabled"
|
||||
}
|
||||
}
|
||||
}
|
||||
Row {
|
||||
id: iconRowMac
|
||||
visible : isDarwin
|
||||
spacing : Style.titleMacOS.leftMargin
|
||||
anchors {
|
||||
left : parent.left
|
||||
verticalCenter : parent.verticalCenter
|
||||
leftMargin : Style.title.leftMargin
|
||||
}
|
||||
Image {
|
||||
id: iconRed
|
||||
width : Style.titleMacOS.imgHeight
|
||||
height : Style.titleMacOS.imgHeight
|
||||
fillMode : Image.PreserveAspectFit
|
||||
smooth : true
|
||||
state : "normal"
|
||||
states: [
|
||||
State { name: "normal" ; PropertyChanges { target: iconRed ; source: "images/macos_red.png" } },
|
||||
State { name: "hover" ; PropertyChanges { target: iconRed ; source: "images/macos_red_hl.png" } },
|
||||
State { name: "pressed" ; PropertyChanges { target: iconRed ; source: "images/macos_red_dark.png" } },
|
||||
State { name: "disabled" ; PropertyChanges { target: iconRed ; source: "images/macos_gray.png" } }
|
||||
]
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
property string beforePressed : "normal"
|
||||
onClicked : {
|
||||
window.close()
|
||||
}
|
||||
onPressed: {
|
||||
beforePressed = parent.state
|
||||
parent.state="pressed"
|
||||
}
|
||||
onReleased: {
|
||||
parent.state=beforePressed
|
||||
}
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: qsTr("Close", "Close the window button")
|
||||
Accessible.description: Accessible.name
|
||||
Accessible.ignored: !parent.visible
|
||||
Accessible.onPressAction: {
|
||||
window.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
Image {
|
||||
id: iconYellow
|
||||
width : Style.titleMacOS.imgHeight
|
||||
height : Style.titleMacOS.imgHeight
|
||||
fillMode : Image.PreserveAspectFit
|
||||
smooth : true
|
||||
state : "disabled"
|
||||
states: [
|
||||
State { name: "normal" ; PropertyChanges { target: iconYellow ; source: "images/macos_yellow.png" } },
|
||||
State { name: "hover" ; PropertyChanges { target: iconYellow ; source: "images/macos_yellow_hl.png" } },
|
||||
State { name: "pressed" ; PropertyChanges { target: iconYellow ; source: "images/macos_yellow_dark.png" } },
|
||||
State { name: "disabled" ; PropertyChanges { target: iconYellow ; source: "images/macos_gray.png" } }
|
||||
]
|
||||
/*
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
property string beforePressed : "normal"
|
||||
onClicked : {
|
||||
window.visibility = Window.Minimized
|
||||
}
|
||||
onPressed: {
|
||||
beforePressed = parent.state
|
||||
parent.state="pressed"
|
||||
}
|
||||
onReleased: {
|
||||
parent.state=beforePressed
|
||||
}
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: qsTr("Minimize", "Minimize the window button")
|
||||
Accessible.description: Accessible.name
|
||||
Accessible.ignored: !parent.visible
|
||||
Accessible.onPressAction: {
|
||||
window.visibility = Window.Minimized
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
Image {
|
||||
id: iconGreen
|
||||
width : Style.titleMacOS.imgHeight
|
||||
height : Style.titleMacOS.imgHeight
|
||||
fillMode : Image.PreserveAspectFit
|
||||
smooth : true
|
||||
source : "images/macos_gray.png"
|
||||
Component.onCompleted : {
|
||||
visible = false // (window.flags&Qt.Dialog) != Qt.Dialog
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Windows
|
||||
Image {
|
||||
id: logo
|
||||
visible: !isDarwin
|
||||
anchors {
|
||||
left : parent.left
|
||||
verticalCenter : parent.verticalCenter
|
||||
leftMargin : Style.title.leftMargin
|
||||
}
|
||||
height : Style.title.fontSize-2*Style.px
|
||||
fillMode : Image.PreserveAspectFit
|
||||
mipmap : true
|
||||
source : "images/pm_logo.png"
|
||||
}
|
||||
|
||||
Row {
|
||||
id: iconRowWin
|
||||
visible: !isDarwin
|
||||
anchors {
|
||||
right : parent.right
|
||||
verticalCenter : root.verticalCenter
|
||||
}
|
||||
Rectangle {
|
||||
height : root.height
|
||||
width : 1.5*height
|
||||
color: Style.transparent
|
||||
Image {
|
||||
id: iconDash
|
||||
anchors.centerIn: parent
|
||||
height : iconTimes.height*0.90
|
||||
fillMode : Image.PreserveAspectFit
|
||||
mipmap : true
|
||||
source : "images/win10_Dash.png"
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill : parent
|
||||
hoverEnabled : true
|
||||
onClicked : {
|
||||
window.visibility = Window.Minimized
|
||||
}
|
||||
onPressed: {
|
||||
parent.scale=0.92
|
||||
}
|
||||
onReleased: {
|
||||
parent.scale=1
|
||||
}
|
||||
onEntered: {
|
||||
parent.color= Qt.lighter(Style.title.background,1.2)
|
||||
}
|
||||
onExited: {
|
||||
parent.color=Style.transparent
|
||||
}
|
||||
|
||||
Accessible.role : Accessible.Button
|
||||
Accessible.name : qsTr("Minimize", "Minimize the window button")
|
||||
Accessible.description : Accessible.name
|
||||
Accessible.ignored : !parent.visible
|
||||
Accessible.onPressAction : {
|
||||
window.visibility = Window.Minimized
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
height : root.height
|
||||
width : 1.5*height
|
||||
color : Style.transparent
|
||||
Image {
|
||||
id: iconTimes
|
||||
anchors.centerIn : parent
|
||||
mipmap : true
|
||||
height : parent.height/1.5
|
||||
fillMode : Image.PreserveAspectFit
|
||||
source : "images/win10_Times.png"
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill : parent
|
||||
hoverEnabled : true
|
||||
onClicked : window.close()
|
||||
onPressed : {
|
||||
iconTimes.scale=0.92
|
||||
}
|
||||
onReleased: {
|
||||
parent.scale=1
|
||||
}
|
||||
onEntered: {
|
||||
parent.color=Style.main.textRed
|
||||
}
|
||||
onExited: {
|
||||
parent.color=Style.transparent
|
||||
}
|
||||
|
||||
Accessible.role : Accessible.Button
|
||||
Accessible.name : qsTr("Close", "Close the window button")
|
||||
Accessible.description : Accessible.name
|
||||
Accessible.ignored : !parent.visible
|
||||
Accessible.onPressAction : {
|
||||
window.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
internal/frontend/qml/ProtonUI/qmldir
Normal file
31
internal/frontend/qml/ProtonUI/qmldir
Normal file
@ -0,0 +1,31 @@
|
||||
module ProtonUI
|
||||
singleton Style 1.0 Style.qml
|
||||
AccessibleButton 1.0 AccessibleButton.qml
|
||||
AccessibleText 1.0 AccessibleText.qml
|
||||
AccessibleSelectableText 1.0 AccessibleSelectableText.qml
|
||||
AccountView 1.0 AccountView.qml
|
||||
AddAccountBar 1.0 AddAccountBar.qml
|
||||
BubbleNote 1.0 BubbleNote.qml
|
||||
BugReportWindow 1.0 BugReportWindow.qml
|
||||
ButtonIconText 1.0 ButtonIconText.qml
|
||||
ButtonRounded 1.0 ButtonRounded.qml
|
||||
CheckBoxLabel 1.0 CheckBoxLabel.qml
|
||||
ClickIconText 1.0 ClickIconText.qml
|
||||
Dialog 1.0 Dialog.qml
|
||||
DialogAddUser 1.0 DialogAddUser.qml
|
||||
DialogUpdate 1.0 DialogUpdate.qml
|
||||
DialogConnectionTroubleshoot 1.0 DialogConnectionTroubleshoot.qml
|
||||
FileAndFolderSelect 1.0 FileAndFolderSelect.qml
|
||||
InfoToolTip 1.0 InfoToolTip.qml
|
||||
InformationBar 1.0 InformationBar.qml
|
||||
InputBox 1.0 InputBox.qml
|
||||
InputField 1.0 InputField.qml
|
||||
InstanceExistsWindow 1.0 InstanceExistsWindow.qml
|
||||
LogoHeader 1.0 LogoHeader.qml
|
||||
PopupMessage 1.0 PopupMessage.qml
|
||||
TabButton 1.0 TabButton.qml
|
||||
TabLabels 1.0 TabLabels.qml
|
||||
TextLabel 1.0 TextLabel.qml
|
||||
TextValue 1.0 TextValue.qml
|
||||
TLSCertPinIssueBar 1.0 TLSCertPinIssueBar.qml
|
||||
WindowTitleBar 1.0 WindowTitleBar.qml
|
||||
611
internal/frontend/qml/tst_Gui.qml
Normal file
611
internal/frontend/qml/tst_Gui.qml
Normal file
@ -0,0 +1,611 @@
|
||||
// Copyright (c) 2020 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/>.
|
||||
|
||||
import QtQuick 2.8
|
||||
import QtTest 1.2
|
||||
import BridgeUI 1.0
|
||||
import ProtonUI 1.0
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Window 2.2
|
||||
|
||||
Window {
|
||||
id: testroot
|
||||
width : 150
|
||||
height : 600
|
||||
flags : Qt.Window | Qt.Dialog | Qt.FramelessWindowHint
|
||||
visible : true
|
||||
title : "GUI test Window"
|
||||
color : "transparent"
|
||||
|
||||
property bool newVersion : true
|
||||
|
||||
Accessible.name: testroot.title
|
||||
Accessible.description: "Window with buttons testing the GUI events"
|
||||
|
||||
|
||||
Rectangle {
|
||||
id:test_systray
|
||||
anchors{
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
height: 40
|
||||
width: testroot.width
|
||||
color: "yellow"
|
||||
Image {
|
||||
id: sysImg
|
||||
anchors {
|
||||
left : test_systray.left
|
||||
top : test_systray.top
|
||||
}
|
||||
height: test_systray.height
|
||||
mipmap: true
|
||||
fillMode : Image.PreserveAspectFit
|
||||
source: ""
|
||||
}
|
||||
Text {
|
||||
id: systrText
|
||||
anchors {
|
||||
right : test_systray.right
|
||||
verticalCenter: test_systray.verticalCenter
|
||||
}
|
||||
text: "unset"
|
||||
}
|
||||
|
||||
function normal() {
|
||||
test_systray.color = "#22ee22"
|
||||
systrText.text = "norm"
|
||||
sysImg.source= "../share/icons/black-systray.png"
|
||||
}
|
||||
function highlight() {
|
||||
test_systray.color = "#eeee22"
|
||||
systrText.text = "highl"
|
||||
sysImg.source= "../share/icons/black-syswarn.png"
|
||||
}
|
||||
function error() {
|
||||
test_systray.color = "#ee2222"
|
||||
systrText.text = "error"
|
||||
sysImg.source= "../share/icons/black-syserror.png"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
property point diff: "0,0"
|
||||
anchors.fill: parent
|
||||
onPressed: {
|
||||
diff = Qt.point(testroot.x, testroot.y)
|
||||
var mousePos = mapToGlobal(mouse.x, mouse.y)
|
||||
diff.x -= mousePos.x
|
||||
diff.y -= mousePos.y
|
||||
}
|
||||
onPositionChanged: {
|
||||
var currPos = mapToGlobal(mouse.x, mouse.y)
|
||||
testroot.x = currPos.x + diff.x
|
||||
testroot.y = currPos.y + diff.y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: buttons
|
||||
|
||||
ListElement { title: "Show window" }
|
||||
ListElement { title: "Show help" }
|
||||
ListElement { title: "Show quit" }
|
||||
ListElement { title: "Logout bridge" }
|
||||
ListElement { title: "Internet on" }
|
||||
ListElement { title: "Internet off" }
|
||||
ListElement { title: "NeedUpdate" }
|
||||
ListElement { title: "UpToDate" }
|
||||
ListElement { title: "ForceUpdate" }
|
||||
ListElement { title: "Linux" }
|
||||
ListElement { title: "Windows" }
|
||||
ListElement { title: "Macos" }
|
||||
ListElement { title: "FirstDialog" }
|
||||
ListElement { title: "AutostartError" }
|
||||
ListElement { title: "BusyPortIMAP" }
|
||||
ListElement { title: "BusyPortSMTP" }
|
||||
ListElement { title: "BusyPortBOTH" }
|
||||
ListElement { title: "Minimize this" }
|
||||
ListElement { title: "SendAlertPopup" }
|
||||
ListElement { title: "TLSCertError" }
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: view
|
||||
anchors {
|
||||
top : test_systray.bottom
|
||||
bottom : parent.bottom
|
||||
left : parent.left
|
||||
right : parent.right
|
||||
}
|
||||
|
||||
orientation : ListView.Vertical
|
||||
model : buttons
|
||||
focus : true
|
||||
|
||||
delegate : ButtonRounded {
|
||||
text : title
|
||||
color_main : "orange"
|
||||
color_minor : "#aa335588"
|
||||
isOpaque : true
|
||||
width: testroot.width
|
||||
height : 20*Style.px
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onClicked : {
|
||||
console.log("Clicked on ", title)
|
||||
switch (title) {
|
||||
case "Show window" :
|
||||
go.showWindow();
|
||||
break;
|
||||
case "Show help" :
|
||||
go.showHelp();
|
||||
break;
|
||||
case "Show quit" :
|
||||
go.showQuit();
|
||||
break;
|
||||
case "Logout bridge" :
|
||||
go.checkLoggedOut("bridge");
|
||||
break;
|
||||
case "Internet on" :
|
||||
go.setConnectionStatus(true);
|
||||
break;
|
||||
case "Internet off" :
|
||||
go.setConnectionStatus(false);
|
||||
break;
|
||||
case "Linux" :
|
||||
go.goos = "linux";
|
||||
break;
|
||||
case "Macos" :
|
||||
go.goos = "darwin";
|
||||
break;
|
||||
case "Windows" :
|
||||
go.goos = "windows";
|
||||
break;
|
||||
case "FirstDialog" :
|
||||
testgui.winMain.dialogFirstStart.show();
|
||||
break;
|
||||
case "AutostartError" :
|
||||
go.notifyBubble(1,go.failedAutostart);
|
||||
break;
|
||||
case "BusyPortIMAP" :
|
||||
go.notifyPortIssue(true,false);
|
||||
break;
|
||||
case "BusyPortSMTP" :
|
||||
go.notifyPortIssue(false,true);
|
||||
break;
|
||||
case "BusyPortBOTH" :
|
||||
go.notifyPortIssue(true,true);
|
||||
break;
|
||||
case "Minimize this" :
|
||||
testroot.visibility = Window.Minimized
|
||||
break;
|
||||
case "UpToDate" :
|
||||
testroot.newVersion = false
|
||||
break;
|
||||
case "NeedUpdate" :
|
||||
testroot.newVersion = true
|
||||
break;
|
||||
case "ForceUpdate" :
|
||||
go.notifyUpdate()
|
||||
break;
|
||||
case "SendAlertPopup" :
|
||||
go.showOutgoingNoEncPopup("Alert sending unencrypted!")
|
||||
break;
|
||||
case "TLSCertError" :
|
||||
go.showCertIssue()
|
||||
break;
|
||||
default :
|
||||
console.log("Not implemented " + data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component.onCompleted : {
|
||||
testroot.x= 10
|
||||
testroot.y= 100
|
||||
}
|
||||
|
||||
//InstanceExistsWindow { id: ie_test }
|
||||
|
||||
Gui {
|
||||
id: testgui
|
||||
|
||||
ListModel{
|
||||
id: accountsModel
|
||||
ListElement{ account : "bridge" ; status : "connected"; isExpanded: false; isCombinedAddressMode: false; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "bridge@pm.com;bridge2@pm.com;theHorriblySlowMurderWithExtremelyInefficientWeapon@youtube.com" }
|
||||
ListElement{ account : "exteremelongnamewhichmustbeeladed@protonmail.com" ; status : "connected"; isExpanded: true; isCombinedAddressMode: true; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "bridge@pm.com;bridge2@pm.com;hu@hu.hu" }
|
||||
ListElement{ account : "bridge2@protonmail.com" ; status : "disconnected"; isExpanded: false; isCombinedAddressMode: false; hostname : "127.0.0.1"; password : "ZI9tKp+ryaxmbpn2E12"; security : "StarTLS"; portSMTP : 1025; portIMAP : 1143; aliases : "bridge@pm.com;bridge2@pm.com;hu@hu.hu" }
|
||||
}
|
||||
|
||||
Component.onCompleted : {
|
||||
winMain.x = testroot.x + testroot.width
|
||||
winMain.y = testroot.y
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QtObject {
|
||||
id: go
|
||||
|
||||
property bool isAutoStart : true
|
||||
property bool isProxyAllowed : false
|
||||
property bool isFirstStart : false
|
||||
property bool isFreshVersion : false
|
||||
property bool isOutdateVersion : true
|
||||
property string currentAddress : "none"
|
||||
//property string goos : "windows"
|
||||
property string goos : "linux"
|
||||
////property string goos : "darwin"
|
||||
property bool isDefaultPort : false
|
||||
property bool isShownOnStart : true
|
||||
|
||||
property bool hasNoKeychain : true
|
||||
|
||||
property string wrongCredentials
|
||||
property string wrongMailboxPassword
|
||||
property string canNotReachAPI
|
||||
property string versionCheckFailed
|
||||
property string credentialsNotRemoved
|
||||
property string bugNotSent
|
||||
property string bugReportSent
|
||||
property string failedAutostartPerm
|
||||
property string failedAutostart
|
||||
property string genericErrSeeLogs
|
||||
|
||||
property string programTitle : "ProtonMail Bridge"
|
||||
property string newversion : "QA.1.0"
|
||||
property string fullversion : "QA.1.0 (d9f8sdf9) 2020-02-19T10:57:23+01:00"
|
||||
property string landingPage : "https://landing.page"
|
||||
//property string downloadLink: "https://landing.page/download/link"
|
||||
property string downloadLink: "https://protonmail.com/download/beta/protonmail-bridge-1.1.5-1.x86_64.rpm;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;https://www.protonmail.com/downloads/beta/Desktop-Bridge-link1.exe;"
|
||||
//property string changelog : "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
|
||||
property string changelog : "• Support of encryption to external PGP recipients using contacts created on beta.protonmail.com (see https://protonmail.com/blog/pgp-vulnerability-efail/ to understand the vulnerabilities that may be associated with sending to other PGP clients)\n• Notification that outgoing email will be delivered as non-encrypted.\n• NOTE: Due to a change of the keychain format, you will need to add your account(s) to the Bridge after installing this version"
|
||||
property string bugfixes : "• Support accounts with same user names\n• Support sending vCalendar event"
|
||||
property string credits : "here;goes;list;;of;;used;packages;"
|
||||
|
||||
property real progress: 0.3
|
||||
property int progressDescription: 2
|
||||
|
||||
|
||||
signal toggleMainWin(int systX, int systY, int systW, int systH)
|
||||
|
||||
signal showWindow()
|
||||
signal showHelp()
|
||||
signal showQuit()
|
||||
|
||||
signal notifyPortIssue(bool busyPortIMAP, bool busyPortSMTP)
|
||||
signal notifyVersionIsTheLatest()
|
||||
signal setUpdateState(string updateState)
|
||||
signal notifyKeychainRebuild()
|
||||
signal notifyHasNoKeychain()
|
||||
|
||||
signal processFinished()
|
||||
signal toggleAutoStart()
|
||||
signal notifyBubble(int tabIndex, string message)
|
||||
signal silentBubble(int tabIndex, string message)
|
||||
signal runCheckVersion(bool showMessage)
|
||||
signal setAddAccountWarning(string message)
|
||||
|
||||
signal notifyUpdate()
|
||||
signal notifyFirewall()
|
||||
signal notifyLogout(string accname)
|
||||
signal notifyAddressChanged(string accname)
|
||||
signal notifyAddressChangedLogout(string accname)
|
||||
signal failedAutostartCode(string code)
|
||||
|
||||
signal showCertIssue()
|
||||
|
||||
signal updateFinished(bool hasError)
|
||||
|
||||
|
||||
signal showOutgoingNoEncPopup(string subject)
|
||||
signal setOutgoingNoEncPopupCoord(real x, real y)
|
||||
signal showNoActiveKeyForRecipient(string recipient)
|
||||
|
||||
function delay(duration) {
|
||||
var timeStart = new Date().getTime();
|
||||
|
||||
while (new Date().getTime() - timeStart < duration) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
function getLastMailClient() {
|
||||
return "Mutt is the best"
|
||||
}
|
||||
|
||||
function sendBug(desc,client,address){
|
||||
console.log("bug report ", "desc '"+desc+"'", "client '"+client+"'", "address '"+address+"'")
|
||||
return !desc.includes("fail")
|
||||
}
|
||||
|
||||
function deleteAccount(index,remove) {
|
||||
console.log ("Test: Delete account ",index," and remove prefences "+remove)
|
||||
workAndClose()
|
||||
accountsModel.remove(index)
|
||||
}
|
||||
|
||||
function logoutAccount(index) {
|
||||
accountsModel.get(index).status="disconnected"
|
||||
workAndClose()
|
||||
}
|
||||
|
||||
function login(username,password) {
|
||||
delay(700)
|
||||
if (password=="wrong") {
|
||||
setAddAccountWarning("Wrong password")
|
||||
return -1
|
||||
}
|
||||
if (username=="2fa") {
|
||||
return 1
|
||||
}
|
||||
if (username=="mbox") {
|
||||
return 2
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
function auth2FA(twoFACode){
|
||||
delay(700)
|
||||
if (twoFACode=="wrong") {
|
||||
setAddAccountWarning("Wrong 2FA")
|
||||
return -1
|
||||
}
|
||||
if (twoFACode=="mbox") {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
function addAccount(mailboxPass) {
|
||||
delay(700)
|
||||
if (mailboxPass=="wrong") {
|
||||
setAddAccountWarning("Wrong mailbox password")
|
||||
return -1
|
||||
}
|
||||
accountsModel.append({
|
||||
"account" : testgui.winMain.dialogAddUser.username,
|
||||
"status" : "connected",
|
||||
"isExpanded":true,
|
||||
"hostname" : "127.0.0.1",
|
||||
"password" : "ZI9tKp+ryaxmbpn2E12",
|
||||
"security" : "StarTLS",
|
||||
"portSMTP" : 1025,
|
||||
"portIMAP" : 1143,
|
||||
"aliases" : "bridge@pm.com;bridges@pm.com;theHorriblySlowMurderWithExtremelyInefficientWeapon@youtube.com",
|
||||
"isCombinedAddressMode": true
|
||||
})
|
||||
workAndClose()
|
||||
}
|
||||
|
||||
function checkInternet() {
|
||||
var delay = Qt.createQmlObject("import QtQuick 2.8; Timer{}",go)
|
||||
delay.interval = 2000
|
||||
delay.repeat = false
|
||||
delay.triggered.connect(function(){ go.setConnectionStatus(false) })
|
||||
delay.start()
|
||||
}
|
||||
|
||||
property SequentialAnimation animateProgressBar : SequentialAnimation {
|
||||
// version
|
||||
PropertyAnimation{ target: go; properties: "progressDescription"; to: 1; duration: 1; }
|
||||
PropertyAnimation{ duration: 2000; }
|
||||
|
||||
// download
|
||||
PropertyAnimation{ target: go; properties: "progressDescription"; to: 2; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.01; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.1; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.3; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.5; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.8; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 1.0; duration: 1; }
|
||||
PropertyAnimation{ duration: 1000; }
|
||||
|
||||
// verify
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.0; duration: 1; }
|
||||
PropertyAnimation{ target: go; properties: "progressDescription"; to: 3; duration: 1; }
|
||||
PropertyAnimation{ duration: 2000; }
|
||||
|
||||
// unzip
|
||||
PropertyAnimation{ target: go; properties: "progressDescription"; to: 4; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.01; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.1; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.3; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.5; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.8; duration: 1; }
|
||||
PropertyAnimation{ duration: 500; }
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 1.0; duration: 1; }
|
||||
PropertyAnimation{ duration: 2000; }
|
||||
|
||||
// update
|
||||
PropertyAnimation{ target: go; properties: "progress"; to: 0.0; duration: 1; }
|
||||
PropertyAnimation{ target: go; properties: "progressDescription"; to: 5; duration: 1; }
|
||||
PropertyAnimation{ duration: 2000; }
|
||||
|
||||
// quit
|
||||
PropertyAnimation{ target: go; properties: "progressDescription"; to: 6; duration: 1; }
|
||||
PropertyAnimation{ duration: 2000; }
|
||||
|
||||
}
|
||||
|
||||
property Timer timer : Timer {
|
||||
id: timer
|
||||
interval : 700
|
||||
repeat : false
|
||||
property string work
|
||||
onTriggered : {
|
||||
console.log("triggered "+timer.work)
|
||||
switch (timer.work) {
|
||||
case "wait":
|
||||
break
|
||||
case "startUpdate":
|
||||
go.animateProgressBar.start()
|
||||
go.updateFinished(true)
|
||||
default:
|
||||
go.processFinished()
|
||||
}
|
||||
}
|
||||
}
|
||||
function workAndClose() {
|
||||
timer.work="default"
|
||||
timer.start()
|
||||
}
|
||||
|
||||
function startUpdate() {
|
||||
timer.work="startUpdate"
|
||||
timer.start()
|
||||
}
|
||||
|
||||
function loadAccounts() {
|
||||
console.log("Test: Account loaded")
|
||||
}
|
||||
|
||||
|
||||
function openDownloadLink(){
|
||||
}
|
||||
|
||||
function switchAddressMode(username){
|
||||
for (var iAcc=0; iAcc < accountsModel.count; iAcc++) {
|
||||
if (accountsModel.get(iAcc).account == username ) {
|
||||
accountsModel.get(iAcc).isCombinedAddressMode = !accountsModel.get(iAcc).isCombinedAddressMode
|
||||
break
|
||||
}
|
||||
}
|
||||
workAndClose()
|
||||
}
|
||||
|
||||
function getLocalVersionInfo(){
|
||||
go.newversion = "QA.1.0"
|
||||
}
|
||||
|
||||
function isNewVersionAvailable(showMessage){
|
||||
if (testroot.newVersion) {
|
||||
go.newversion = "QA.2.0"
|
||||
setUpdateState("oldVersion")
|
||||
} else {
|
||||
go.newversion = "QA.1.0"
|
||||
setUpdateState("upToDate")
|
||||
if(showMessage) {
|
||||
notifyVersionIsTheLatest()
|
||||
}
|
||||
}
|
||||
workAndClose()
|
||||
}
|
||||
|
||||
function getBackendVersion() {
|
||||
return "BridgeUI 1.0"
|
||||
}
|
||||
|
||||
property bool isConnectionOK : true
|
||||
signal setConnectionStatus(bool isAvailable)
|
||||
|
||||
function configureAppleMail(iAccount,iAddress) {
|
||||
console.log ("Test: autoconfig account ",iAccount," address ",iAddress)
|
||||
}
|
||||
|
||||
function openLogs() {
|
||||
Qt.openUrlExternally("file:///home/dev/")
|
||||
}
|
||||
|
||||
function highlightSystray() {
|
||||
test_systray.highlight()
|
||||
}
|
||||
|
||||
function errorSystray() {
|
||||
test_systray.error()
|
||||
}
|
||||
|
||||
function normalSystray() {
|
||||
test_systray.normal()
|
||||
}
|
||||
|
||||
signal bubbleClosed()
|
||||
|
||||
function getIMAPPort() {
|
||||
return 1143
|
||||
}
|
||||
function getSMTPPort() {
|
||||
return 1025
|
||||
}
|
||||
|
||||
function isPortOpen(portstring){
|
||||
if (isNaN(portstring)) {
|
||||
return 1
|
||||
}
|
||||
var portnum = parseInt(portstring,10)
|
||||
if (portnum < 3333) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
property bool isRestarting: false
|
||||
function setPortsAndSecurity(portIMAP, portSMTP, secSMTP) {
|
||||
console.log("Test: ports changed", portIMAP, portSMTP, secSMTP)
|
||||
}
|
||||
|
||||
function isSMTPSTARTTLS() {
|
||||
return true
|
||||
}
|
||||
|
||||
signal openManual()
|
||||
|
||||
function clearCache() {
|
||||
workAndClose()
|
||||
}
|
||||
|
||||
function clearKeychain() {
|
||||
workAndClose()
|
||||
}
|
||||
|
||||
property bool isReportingOutgoingNoEnc : true
|
||||
|
||||
function toggleIsReportingOutgoingNoEnc() {
|
||||
go.isReportingOutgoingNoEnc = !go.isReportingOutgoingNoEnc
|
||||
console.log("Reporting changed to ", go.isReportingOutgoingNoEnc)
|
||||
}
|
||||
|
||||
function saveOutgoingNoEncPopupCoord(x,y) {
|
||||
console.log("Triggered saveOutgoingNoEncPopupCoord: ",x,y)
|
||||
}
|
||||
|
||||
function shouldSendAnswer (messageID, shouldSend) {
|
||||
if (shouldSend) console.log("answered to send email")
|
||||
else console.log("answered to cancel email")
|
||||
}
|
||||
|
||||
onToggleAutoStart: {
|
||||
workAndClose()
|
||||
isAutoStart = (isAutoStart!=false) ? false : true
|
||||
console.log (" Test: toggleAutoStart "+isAutoStart)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user