We build too many walls and not enough bridges

This commit is contained in:
Jakub
2020-04-08 12:59:16 +02:00
commit 17f4d6097a
494 changed files with 62753 additions and 0 deletions

View 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)
}

View 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 == ""
}

View 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
}
}

View 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()
}
}

View 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()
}
}

View 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()
}
}

View 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
}
}

View 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
}
}
}

View 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 } }
]
}

View 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
}
}

View 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
}
}
}

View 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
}
}

View 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()
}
}
}

View 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 cant 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
}
}
}
}

View 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()
}
}

View 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 != ""
}
}

View 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
}
}
}

View 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: ""
}
}
]
}

View 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()
}
}

View 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()
}
}
}

View 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()
}
}

View 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()
}
}
}

View 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
}
}

View 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/>.

File diff suppressed because it is too large Load Diff

View 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
}
}
]
}

View 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"
}
]
}

View 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)
}
}

View 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
}
}
]
}

View 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
}
}

View 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()
}
}
}
}
}

View 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