GODT-1554 / 1555: Implement gRPC go service and Qt 5 frontend C++ app.
WIP: updates WIP: cache on disk and autostart. WIP: mail, keychain and more. WIP: updated grpc version in go mod file. WIP: user list. WIP: RPC service placeholder WIP: test C++ RPC client skeleton. Other: missing license script update. WIP: use Qt test framework. WIP: test for app and login calls. WIP: test for update & cache on disk calls. WIP: tests for mail settings calls. WIP: all client tests. WIP: linter fixes. WIP: fix missing license link. WIP: update dependency_license script for gRPC and protobuf. WIP: removed unused file. WIP: app & login event streaming tests. WIP: update event stream tests. WIP: completed event streaming tests. GODT-1554: qt C++ frontend skeleton. WIP: C++ backend declaration. wip: started drafting user model. WIP: users. not functional. WIP: invokable methods WIP: Exception class + backend 'injection' into QML. WIP: switch to VCPKG to ease multi-arch compilation, C++ RPC client skeleton. WIP: Renaming and reorganisation WIP:introduced new 'grpc' go frontend. WIP: Worker & Oveerseer for thread management. WIP: added log to C++ app. WIP: event stream architecture on Go side. WIP: event parsing and streamer stopping. WIP: Moved grpc to frontend subfolder + use vcpkg for gRPC and protobuf. WIP: windows building ok WIP: wired a few messages WIP: more wiring. WIP: Fixed imports after rebase on top of devel. WIP: wired some bool and string properties. WIP: more properties. WIP: wired cache on disk stuff WIP: connect event watcher. WIP: login WIP: fix showSplashScreen WIP: Wired login calls. WIP: user list. WIP: Refactored main(). WIP: User retrieval . WIP: no shared pointer in user model. WIP: fixed user count. WIP: cached goos. WIP: Wired autostart WIP: beta channel toggle wired. WIP: User removal WIP: wired theme WIP: implemented configure apple mail. WIP: split mode. WIP: fixed user updates. WIP: fixed Quit from tray icon WIP: wired CurrentEmailClient WIP: wired UseSSLForSMTP WIP: wired change ports . WIP: wired DoH. . WIP: wired keychain calls. WIP: wired autoupdate option. WIP: QML Backend clean-up. WIP: cleanup. WIP: moved user related files in subfolder. . WIP: User are managed using smart pointers. WIP: cleanup. WIP: more cleanup. WIP: mail events forwarding WIP: code inspection tweaks from CLion. WIP: moved QML, cleanup, and missing copyright notices. WIP: Backend is not QMLBackend. Other: fixed issues reported by Leander. [skip ci]
190
internal/frontend/qt6/qml/AccountDelegate.qml
Normal file
@ -0,0 +1,190 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property ColorScheme colorScheme
|
||||
property var user
|
||||
|
||||
property var _spacing: 12 * ProtonStyle.px
|
||||
|
||||
property color usedSpaceColor : {
|
||||
if (!root.enabled) return root.colorScheme.text_weak
|
||||
if (root.type == AccountDelegate.SmallView) return root.colorScheme.text_weak
|
||||
if (root.usedFraction < .50) return root.colorScheme.signal_success
|
||||
if (root.usedFraction < .75) return root.colorScheme.signal_warning
|
||||
return root.colorScheme.signal_danger
|
||||
}
|
||||
property real usedFraction: root.user ? reasonableFracion(root.user.usedBytes, root.user.totalBytes) : 0
|
||||
property string totalSpace: root.spaceWithUnits(root.user ? root.reasonableBytes(root.user.totalBytes) : 0)
|
||||
property string usedSpace: root.spaceWithUnits(root.user ? root.reasonableBytes(root.user.usedBytes) : 0)
|
||||
|
||||
function reasonableFracion(used, total){
|
||||
var usedSafe = root.reasonableBytes(used)
|
||||
var totalSafe = root.reasonableBytes(total)
|
||||
if (totalSafe == 0 || usedSafe == 0) return 0
|
||||
if (totalSafe <= usedSafe) return 1
|
||||
return usedSafe / totalSafe
|
||||
}
|
||||
|
||||
function reasonableBytes(bytes){
|
||||
var safeBytes = bytes+0
|
||||
if (safeBytes != bytes) return 0
|
||||
if (safeBytes < 0) return 0
|
||||
return Math.ceil(safeBytes)
|
||||
}
|
||||
|
||||
function spaceWithUnits(bytes){
|
||||
if (bytes*1 !== bytes || bytes == 0 ) return "0 kB"
|
||||
var units = ['B',"kB", "MB", "GB", "TB"];
|
||||
var i = parseInt(Math.floor(Math.log(bytes)/Math.log(1024)));
|
||||
|
||||
return Math.round(bytes*10 / Math.pow(1024, i))/10 + " " + units[i]
|
||||
}
|
||||
|
||||
// width expected to be set by parent object
|
||||
implicitHeight : children[0].implicitHeight
|
||||
|
||||
enum ViewType{
|
||||
SmallView, LargeView
|
||||
}
|
||||
property var type : AccountDelegate.SmallView
|
||||
|
||||
RowLayout {
|
||||
spacing: root._spacing
|
||||
|
||||
anchors {
|
||||
top: root.top
|
||||
left: root.left
|
||||
right: root.rigth
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: avatar
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: height
|
||||
|
||||
radius: ProtonStyle.avatar_radius
|
||||
|
||||
color: root.colorScheme.background_avatar
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
anchors.fill: parent
|
||||
text: root.user ? root.user.avatarText.toUpperCase(): ""
|
||||
type: {
|
||||
switch (root.type) {
|
||||
case AccountDelegate.SmallView: return Label.Body
|
||||
case AccountDelegate.LargeView: return Label.Title
|
||||
}
|
||||
}
|
||||
font.weight: Font.Normal
|
||||
color: "#FFFFFF"
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: account
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
spacing: 0
|
||||
|
||||
Label {
|
||||
Layout.maximumWidth: root.width - (
|
||||
root._spacing + avatar.width
|
||||
)
|
||||
|
||||
colorScheme: root.colorScheme
|
||||
text: root.user ? user.username : ""
|
||||
type: {
|
||||
switch (root.type) {
|
||||
case AccountDelegate.SmallView: return Label.Body
|
||||
case AccountDelegate.LargeView: return Label.Title
|
||||
}
|
||||
}
|
||||
elide: Text.ElideMiddle
|
||||
}
|
||||
|
||||
Item { implicitHeight: root.type == AccountDelegate.LargeView ? 6 * ProtonStyle.px : 0 }
|
||||
|
||||
RowLayout {
|
||||
spacing: 0
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: root.user && root.user.loggedIn ? root.usedSpace : qsTr("Signed out")
|
||||
color: root.usedSpaceColor
|
||||
type: {
|
||||
switch (root.type) {
|
||||
case AccountDelegate.SmallView: return Label.Caption
|
||||
case AccountDelegate.LargeView: return Label.Body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: root.user && root.user.loggedIn ? " / " + root.totalSpace : ""
|
||||
color: root.colorScheme.text_weak
|
||||
type: {
|
||||
switch (root.type) {
|
||||
case AccountDelegate.SmallView: return Label.Caption
|
||||
case AccountDelegate.LargeView: return Label.Body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: storage_bar
|
||||
visible: root.user ? root.type == AccountDelegate.LargeView : false
|
||||
width: 140 * ProtonStyle.px
|
||||
height: 4 * ProtonStyle.px
|
||||
radius: ProtonStyle.storage_bar_radius
|
||||
color: root.colorScheme.border_weak
|
||||
|
||||
Rectangle {
|
||||
id: storage_bar_filled
|
||||
radius: ProtonStyle.storage_bar_radius
|
||||
color: root.usedSpaceColor
|
||||
visible: root.user ? parent.visible && root.user.loggedIn : false
|
||||
anchors {
|
||||
top : parent.top
|
||||
bottom : parent.bottom
|
||||
left : parent.left
|
||||
}
|
||||
width: Math.min(1,Math.max(0.02,root.usedFraction)) * parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
251
internal/frontend/qt6/qml/AccountView.qml
Normal file
@ -0,0 +1,251 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property ColorScheme colorScheme
|
||||
property var backend
|
||||
property var notifications
|
||||
property var user
|
||||
|
||||
signal showSignIn()
|
||||
signal showSetupGuide(var user, string address)
|
||||
|
||||
property int _leftMargin: 64
|
||||
property int _rightMargin: 64
|
||||
property int _topMargin: 32
|
||||
property int _detailsTopMargin: 25
|
||||
property int _bottomMargin: 12
|
||||
property int _spacing: 20
|
||||
property int _lineWidth: 1
|
||||
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
clip: true
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
// can't use parent here because parent is not ScrollView (Flickable inside contentItem inside ScrollView)
|
||||
width: scrollView.availableWidth
|
||||
height: scrollView.availableHeight
|
||||
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
// do not set implicitWidth because implicit width of ColumnLayout will be equal to maximum implicit width of
|
||||
// internal items. And if one of internal items would be a Text or Label - implicit width of those is always
|
||||
// equal to non-wrapped text (i.e. one line only). That will lead to enabling horizontal scroll when not needed
|
||||
implicitWidth: width
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle {
|
||||
id: topRectangle
|
||||
color: root.colorScheme.background_norm
|
||||
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
spacing: root._spacing
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: root._leftMargin
|
||||
anchors.rightMargin: root._rightMargin
|
||||
anchors.topMargin: root._topMargin
|
||||
anchors.bottomMargin: root._bottomMargin
|
||||
|
||||
RowLayout { // account delegate with action buttons
|
||||
Layout.fillWidth: true
|
||||
|
||||
AccountDelegate {
|
||||
Layout.fillWidth: true
|
||||
colorScheme: root.colorScheme
|
||||
user: root.user
|
||||
type: AccountDelegate.LargeView
|
||||
enabled: root.user ? root.user.loggedIn : false
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Sign out")
|
||||
secondary: true
|
||||
visible: root.user ? root.user.loggedIn : false
|
||||
onClicked: {
|
||||
if (!root.user) return
|
||||
root.user.logout()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Sign in")
|
||||
secondary: true
|
||||
visible: root.user ? !root.user.loggedIn : false
|
||||
onClicked: {
|
||||
if (!root.user) return
|
||||
root.showSignIn()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
colorScheme: root.colorScheme
|
||||
icon.source: "icons/ic-trash.svg"
|
||||
secondary: true
|
||||
onClicked: {
|
||||
if (!root.user) return
|
||||
root.notifications.askDeleteAccount(root.user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: root._lineWidth
|
||||
color: root.colorScheme.border_weak
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Email clients")
|
||||
actionText: qsTr("Configure")
|
||||
description: qsTr("Using the mailbox details below (re)configure your client.")
|
||||
type: SettingsItem.Button
|
||||
enabled: root.user ? root.user.loggedIn : false
|
||||
visible: root.user ? !root.user.splitMode || root.user.addresses.length==1 : false
|
||||
showSeparator: splitMode.visible
|
||||
onClicked: {
|
||||
if (!root.user) return
|
||||
root.showSetupGuide(root.user, user.addresses[0])
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: splitMode
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Split addresses")
|
||||
description: qsTr("Setup multiple email addresses individually.")
|
||||
type: SettingsItem.Toggle
|
||||
checked: root.user ? root.user.splitMode : false
|
||||
visible: root.user ? root.user.addresses.length > 1 : false
|
||||
enabled: root.user ? root.user.loggedIn : false
|
||||
showSeparator: addressSelector.visible
|
||||
onClicked: {
|
||||
if (!splitMode.checked){
|
||||
root.notifications.askEnableSplitMode(user)
|
||||
} else {
|
||||
addressSelector.currentIndex = 0
|
||||
root.user.toggleSplitMode(!splitMode.checked)
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
enabled: root.user ? root.user.loggedIn : false
|
||||
visible: root.user ? root.user.splitMode : false
|
||||
|
||||
ComboBox {
|
||||
id: addressSelector
|
||||
colorScheme: root.colorScheme
|
||||
Layout.fillWidth: true
|
||||
model: root.user ? root.user.addresses : null
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Configure")
|
||||
secondary: true
|
||||
onClicked: {
|
||||
if (!root.user) return
|
||||
root.showSetupGuide(root.user, addressSelector.displayText)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: root.colorScheme.background_weak
|
||||
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
id: configuration
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: root._leftMargin
|
||||
anchors.rightMargin: root._rightMargin
|
||||
anchors.topMargin: root._detailsTopMargin
|
||||
anchors.bottomMargin: root._spacing
|
||||
|
||||
spacing: root._spacing
|
||||
visible: root.user ? root.user.loggedIn : false
|
||||
|
||||
property string currentAddress: addressSelector.displayText
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Mailbox details")
|
||||
type: Label.Body_semibold
|
||||
}
|
||||
|
||||
Configuration {
|
||||
colorScheme: root.colorScheme
|
||||
title: qsTr("IMAP")
|
||||
hostname: root.backend.hostname
|
||||
port: root.backend.portIMAP.toString()
|
||||
username: configuration.currentAddress
|
||||
password: root.user ? root.user.password : ""
|
||||
security: "STARTTLS"
|
||||
}
|
||||
|
||||
Configuration {
|
||||
colorScheme: root.colorScheme
|
||||
title: qsTr("SMTP")
|
||||
hostname : root.backend.hostname
|
||||
port : root.backend.portSMTP.toString()
|
||||
username : configuration.currentAddress
|
||||
password : root.user ? root.user.password : ""
|
||||
security : root.backend.useSSLforSMTP ? "SSL" : "STARTTLS"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
234
internal/frontend/qt6/qml/Banner.qml
Normal file
@ -0,0 +1,234 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
|
||||
import Proton 4.0
|
||||
import Notifications 1.0
|
||||
|
||||
Popup {
|
||||
id: root
|
||||
|
||||
property ColorScheme colorScheme
|
||||
property Notification notification
|
||||
property var mainWindow
|
||||
|
||||
topMargin: 37
|
||||
leftMargin: (mainWindow.width - root.implicitWidth)/2
|
||||
|
||||
implicitHeight: contentLayout.implicitHeight + contentLayout.anchors.topMargin + contentLayout.anchors.bottomMargin
|
||||
implicitWidth: 600 // contentLayout.implicitWidth + contentLayout.anchors.leftMargin + contentLayout.anchors.rightMargin
|
||||
|
||||
popupType: ApplicationWindow.PopupType.Banner
|
||||
|
||||
shouldShow: notification ? (notification.active && !notification.dismissed) : false
|
||||
|
||||
modal: false
|
||||
|
||||
Action {
|
||||
id: defaultDismissAction
|
||||
|
||||
text: qsTr("OK")
|
||||
onTriggered: {
|
||||
if (!root.notification) {
|
||||
return
|
||||
}
|
||||
|
||||
root.notification.dismissed = true
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: contentLayout
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
clip: true
|
||||
implicitHeight: children[1].implicitHeight + children[1].anchors.topMargin + children[1].anchors.bottomMargin
|
||||
implicitWidth: children[1].implicitWidth + children[1].anchors.leftMargin + children[1].anchors.rightMargin
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
width: parent.width + 10
|
||||
radius: ProtonStyle.banner_radius
|
||||
color: {
|
||||
if (!root.notification) {
|
||||
return "transparent"
|
||||
}
|
||||
|
||||
switch (root.notification.type) {
|
||||
case Notification.NotificationType.Info:
|
||||
return root.colorScheme.signal_info
|
||||
case Notification.NotificationType.Success:
|
||||
return root.colorScheme.signal_success
|
||||
case Notification.NotificationType.Warning:
|
||||
return root.colorScheme.signal_warning
|
||||
case Notification.NotificationType.Danger:
|
||||
return root.colorScheme.signal_danger
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
anchors.topMargin: 14
|
||||
anchors.bottomMargin: 14
|
||||
anchors.leftMargin: 16
|
||||
|
||||
spacing: 8
|
||||
|
||||
ColorImage {
|
||||
color: root.colorScheme.text_invert
|
||||
width: 24
|
||||
height: 24
|
||||
|
||||
sourceSize.width: 24
|
||||
sourceSize.height: 24
|
||||
|
||||
Layout.preferredHeight: 24
|
||||
Layout.preferredWidth: 24
|
||||
|
||||
source: {
|
||||
if (!root.notification) {
|
||||
return ""
|
||||
}
|
||||
|
||||
switch (root.notification.type) {
|
||||
case Notification.NotificationType.Info:
|
||||
return "./icons/ic-info-circle-filled.svg"
|
||||
case Notification.NotificationType.Success:
|
||||
return "./icons/ic-info-circle-filled.svg"
|
||||
case Notification.NotificationType.Warning:
|
||||
return "./icons/ic-exclamation-circle-filled.svg"
|
||||
case Notification.NotificationType.Danger:
|
||||
return "./icons/ic-exclamation-circle-filled.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.leftMargin: 16
|
||||
|
||||
color: root.colorScheme.text_invert
|
||||
text: root.notification ? root.notification.description : ""
|
||||
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
width: 1
|
||||
color: {
|
||||
if (!root.notification) {
|
||||
return "transparent"
|
||||
}
|
||||
|
||||
switch (root.notification.type) {
|
||||
case Notification.NotificationType.Info:
|
||||
return root.colorScheme.signal_info_active
|
||||
case Notification.NotificationType.Success:
|
||||
return root.colorScheme.signal_success_active
|
||||
case Notification.NotificationType.Warning:
|
||||
return root.colorScheme.signal_warning_active
|
||||
case Notification.NotificationType.Danger:
|
||||
return root.colorScheme.signal_danger_active
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
Layout.fillHeight: true
|
||||
|
||||
id: actionButton
|
||||
|
||||
action: (root.notification && root.notification.action.length > 0) ? root.notification.action[0] : defaultDismissAction
|
||||
|
||||
background: Item {
|
||||
clip: true
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
width: parent.width + 10
|
||||
radius: ProtonStyle.banner_radius
|
||||
color: {
|
||||
if (!root.notification) {
|
||||
return "transparent"
|
||||
}
|
||||
|
||||
var norm
|
||||
var hover
|
||||
var active
|
||||
|
||||
switch (root.notification.type) {
|
||||
case Notification.NotificationType.Info:
|
||||
norm = root.colorScheme.signal_info
|
||||
hover = root.colorScheme.signal_info_hover
|
||||
active = root.colorScheme.signal_info_active
|
||||
break;
|
||||
case Notification.NotificationType.Success:
|
||||
norm = root.colorScheme.signal_success
|
||||
hover = root.colorScheme.signal_success_hover
|
||||
active = root.colorScheme.signal_success_active
|
||||
break;
|
||||
case Notification.NotificationType.Warning:
|
||||
norm = root.colorScheme.signal_warning
|
||||
hover = root.colorScheme.signal_warning_hover
|
||||
active = root.colorScheme.signal_warning_active
|
||||
break;
|
||||
case Notification.NotificationType.Danger:
|
||||
norm = root.colorScheme.signal_danger
|
||||
hover = root.colorScheme.signal_danger_hover
|
||||
active = root.colorScheme.signal_danger_active
|
||||
break;
|
||||
}
|
||||
|
||||
if (actionButton.down) {
|
||||
return active
|
||||
}
|
||||
|
||||
if (actionButton.enabled && (actionButton.highlighted || actionButton.hovered || actionButton.checked)) {
|
||||
return hover
|
||||
}
|
||||
|
||||
if (actionButton.loading) {
|
||||
return hover
|
||||
}
|
||||
|
||||
return norm
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
294
internal/frontend/qt6/qml/Bridge.qml
Normal file
@ -0,0 +1,294 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Window 2.13
|
||||
import Qt.labs.platform 1.1
|
||||
|
||||
import Proton 4.0
|
||||
import Notifications 1.0
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
function isInInterval(num, lower_limit, upper_limit) {
|
||||
return lower_limit <= num && num <= upper_limit
|
||||
}
|
||||
function bound(num, lower_limit, upper_limit) {
|
||||
return Math.max(lower_limit, Math.min(upper_limit, num))
|
||||
}
|
||||
|
||||
property var backend
|
||||
property var title: "Proton Mail Bridge"
|
||||
|
||||
property Notifications _notifications: Notifications {
|
||||
id: notifications
|
||||
backend: root.backend
|
||||
frontendMain: mainWindow
|
||||
frontendStatus: statusWindow
|
||||
frontendTray: trayIcon
|
||||
}
|
||||
|
||||
property MainWindow _mainWindow: MainWindow {
|
||||
id: mainWindow
|
||||
visible: false
|
||||
|
||||
title: root.title
|
||||
backend: root.backend
|
||||
notifications: root._notifications
|
||||
|
||||
onVisibleChanged: {
|
||||
backend.dockIconVisible = visible
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.backend
|
||||
onCacheUnavailable: {
|
||||
mainWindow.showAndRise()
|
||||
}
|
||||
onColorSchemeNameChanged: root.setColorScheme()
|
||||
}
|
||||
}
|
||||
|
||||
property StatusWindow _statusWindow: StatusWindow {
|
||||
id: statusWindow
|
||||
visible: false
|
||||
|
||||
title: root.title
|
||||
backend: root.backend
|
||||
notifications: root._notifications
|
||||
|
||||
onShowMainWindow: {
|
||||
mainWindow.showAndRise()
|
||||
}
|
||||
|
||||
onShowHelp: {
|
||||
mainWindow.showHelp()
|
||||
mainWindow.showAndRise()
|
||||
}
|
||||
|
||||
onShowSettings: {
|
||||
mainWindow.showSettings()
|
||||
mainWindow.showAndRise()
|
||||
}
|
||||
|
||||
onShowSignIn: {
|
||||
mainWindow.showSignIn(username)
|
||||
mainWindow.showAndRise()
|
||||
}
|
||||
|
||||
onQuit: {
|
||||
backend.quit()
|
||||
}
|
||||
|
||||
property rect screenRect
|
||||
property rect iconRect
|
||||
|
||||
// use binding from function with width and height as arguments so it will be recalculated every time width and height are changed
|
||||
property point position: getPosition(width, height)
|
||||
x: position.x
|
||||
y: position.y
|
||||
|
||||
function getPosition(_width, _height) {
|
||||
if (screenRect.width === 0 || screenRect.height === 0) {
|
||||
return Qt.point(0, 0)
|
||||
}
|
||||
|
||||
var _x = 0
|
||||
var _y = 0
|
||||
|
||||
// fit above
|
||||
_y = iconRect.top - height
|
||||
if (isInInterval(_y, screenRect.top, screenRect.bottom - height)) {
|
||||
// position preferebly in the horizontal center but bound to the screen rect
|
||||
_x = bound(iconRect.left + (iconRect.width - width)/2, screenRect.left, screenRect.right - width)
|
||||
return Qt.point(_x, _y)
|
||||
}
|
||||
|
||||
// fit below
|
||||
_y = iconRect.bottom
|
||||
if (isInInterval(_y, screenRect.top, screenRect.bottom - height)) {
|
||||
// position preferebly in the horizontal center but bound to the screen rect
|
||||
_x = bound(iconRect.left + (iconRect.width - width)/2, screenRect.left, screenRect.right - width)
|
||||
return Qt.point(_x, _y)
|
||||
}
|
||||
|
||||
// fit to the left
|
||||
_x = iconRect.left - width
|
||||
if (isInInterval(_x, screenRect.left, screenRect.right - width)) {
|
||||
// position preferebly in the vertical center but bound to the screen rect
|
||||
_y = bound(iconRect.top + (iconRect.height - height)/2, screenRect.top, screenRect.bottom - height)
|
||||
return Qt.point(_x, _y)
|
||||
}
|
||||
|
||||
// fit to the right
|
||||
_x = iconRect.right
|
||||
if (isInInterval(_x, screenRect.left, screenRect.right - width)) {
|
||||
// position preferebly in the vertical center but bound to the screen rect
|
||||
_y = bound(iconRect.top + (iconRect.height - height)/2, screenRect.top, screenRect.bottom - height)
|
||||
return Qt.point(_x, _y)
|
||||
}
|
||||
|
||||
// Fallback: position satatus window right above icon and let window manager decide.
|
||||
console.warn("Can't position status window: screenRect =", screenRect, "iconRect =", iconRect)
|
||||
_x = bound(iconRect.left + (iconRect.width - width)/2, screenRect.left, screenRect.right - width)
|
||||
_y = bound(iconRect.top + (iconRect.height - height)/2, screenRect.top, screenRect.bottom - height)
|
||||
return Qt.point(_x, _y)
|
||||
}
|
||||
}
|
||||
|
||||
property SystemTrayIcon _trayIcon: SystemTrayIcon {
|
||||
id: trayIcon
|
||||
visible: true
|
||||
icon.source: getTrayIconPath()
|
||||
icon.mask: true // make sure that systems like macOS will use proper color
|
||||
tooltip: `${root.title} v${backend.version}`
|
||||
onActivated: {
|
||||
function calcStatusWindowPosition() {
|
||||
// On some platforms (X11 / Plasma) Qt does not provide icon position and geometry info.
|
||||
// In this case we rely on cursor position
|
||||
var iconRect = Qt.rect(geometry.x, geometry.y, geometry.width, geometry.height)
|
||||
if (geometry.width == 0 && geometry.height == 0) {
|
||||
var mousePos = backend.getCursorPos()
|
||||
iconRect.x = mousePos.x
|
||||
iconRect.y = mousePos.y
|
||||
iconRect.width = 0
|
||||
iconRect.height = 0
|
||||
}
|
||||
|
||||
// Find screen
|
||||
var screen
|
||||
for (var i in Qt.application.screens) {
|
||||
var _screen = Qt.application.screens[i]
|
||||
if (
|
||||
isInInterval(iconRect.x, _screen.virtualX, _screen.virtualX + _screen.width) &&
|
||||
isInInterval(iconRect.y, _screen.virtualY, _screen.virtualY + _screen.height)
|
||||
) {
|
||||
screen = _screen
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!screen) {
|
||||
// Fallback to primary screen
|
||||
screen = Qt.application.screens[0]
|
||||
}
|
||||
|
||||
// In case we used mouse to detect icon position - we want to make a fake icon rectangle from a point
|
||||
if (iconRect.width == 0 && iconRect.height == 0) {
|
||||
iconRect.x = bound(iconRect.x - 16, screen.virtualX, screen.virtualX + screen.width - 32)
|
||||
iconRect.y = bound(iconRect.y - 16, screen.virtualY, screen.virtualY + screen.height - 32)
|
||||
iconRect.width = 32
|
||||
iconRect.height = 32
|
||||
}
|
||||
|
||||
statusWindow.screenRect = Qt.rect(screen.virtualX, screen.virtualY, screen.width, screen.height)
|
||||
statusWindow.iconRect = iconRect
|
||||
}
|
||||
|
||||
function toggleWindow(win) {
|
||||
if (win.visible) {
|
||||
win.close()
|
||||
} else {
|
||||
win.showAndRise()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (reason) {
|
||||
case SystemTrayIcon.Unknown:
|
||||
break;
|
||||
case SystemTrayIcon.Context:
|
||||
case SystemTrayIcon.Trigger:
|
||||
case SystemTrayIcon.DoubleClick:
|
||||
case SystemTrayIcon.MiddleClick:
|
||||
calcStatusWindowPosition()
|
||||
toggleWindow(statusWindow)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
property NotificationFilter _systrayfilter: NotificationFilter {
|
||||
source: root._notifications ? root._notifications.all : undefined
|
||||
}
|
||||
|
||||
function getTrayIconPath() {
|
||||
var color = backend.goos == "darwin" ? "mono" : "color"
|
||||
|
||||
var level = "norm"
|
||||
if (_systrayfilter.topmost) {
|
||||
switch (_systrayfilter.topmost.type) {
|
||||
case Notification.NotificationType.Danger:
|
||||
level = "error"
|
||||
break;
|
||||
case Notification.NotificationType.Warning:
|
||||
level = "warn"
|
||||
break;
|
||||
case Notification.NotificationType.Info:
|
||||
level = "update"
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return `./icons/systray-${color}-${level}.png`
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!root.backend) {
|
||||
console.log("backend not loaded")
|
||||
}
|
||||
|
||||
root.setColorScheme()
|
||||
|
||||
|
||||
if (!root.backend.users) {
|
||||
console.log("users not loaded")
|
||||
}
|
||||
|
||||
var c = root.backend.users.count
|
||||
var u = root.backend.users.get(0)
|
||||
// DEBUG
|
||||
if (c != 0) {
|
||||
console.log("users non zero", c)
|
||||
console.log("first user", u )
|
||||
}
|
||||
|
||||
if (c === 0) {
|
||||
mainWindow.showAndRise()
|
||||
}
|
||||
|
||||
if (u) {
|
||||
if (c === 1 && u.loggedIn === false) {
|
||||
mainWindow.showAndRise()
|
||||
}
|
||||
}
|
||||
|
||||
if (root.backend.showOnStartup) {
|
||||
mainWindow.showAndRise()
|
||||
}
|
||||
|
||||
root.backend.guiReady()
|
||||
}
|
||||
|
||||
function setColorScheme() {
|
||||
if (root.backend.colorSchemeName == "light") ProtonStyle.currentStyle = ProtonStyle.lightStyle
|
||||
if (root.backend.colorSchemeName == "dark") ProtonStyle.currentStyle = ProtonStyle.darkStyle
|
||||
}
|
||||
}
|
||||
316
internal/frontend/qt6/qml/BridgeTest/UserControl.qml
Normal file
@ -0,0 +1,316 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property var user
|
||||
property var userIndex
|
||||
property var backend
|
||||
|
||||
spacing : 5
|
||||
|
||||
Layout.fillHeight: true
|
||||
//Layout.fillWidth: true
|
||||
|
||||
property ColorScheme colorScheme
|
||||
|
||||
TextField {
|
||||
colorScheme: root.colorScheme
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: user !== undefined ? user.username : ""
|
||||
|
||||
onEditingFinished: {
|
||||
user.username = text
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Switch {
|
||||
id: userLoginSwitch
|
||||
colorScheme: root.colorScheme
|
||||
|
||||
text: "LoggedIn"
|
||||
enabled: user !== undefined && user.username.length > 0
|
||||
|
||||
checked: user ? user.loggedIn : false
|
||||
|
||||
onCheckedChanged: {
|
||||
if (!user) {
|
||||
return
|
||||
}
|
||||
|
||||
if (checked) {
|
||||
if (user === backend.loginUser) {
|
||||
var newUserObject = backend.userComponent.createObject(backend, {username: user.username, loggedIn: true, setupGuideSeen: user.setupGuideSeen})
|
||||
backend.users.append( { object: newUserObject } )
|
||||
|
||||
user.username = ""
|
||||
user.resetLoginRequests()
|
||||
return
|
||||
}
|
||||
|
||||
user.loggedIn = true
|
||||
user.resetLoginRequests()
|
||||
return
|
||||
} else {
|
||||
user.loggedIn = false
|
||||
user.resetLoginRequests()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Switch {
|
||||
colorScheme: root.colorScheme
|
||||
|
||||
text: "Setup guide seen"
|
||||
enabled: user !== undefined && user.username.length > 0
|
||||
|
||||
checked: user ? user.setupGuideSeen : false
|
||||
|
||||
onCheckedChanged: {
|
||||
if (!user) {
|
||||
return
|
||||
}
|
||||
|
||||
user.setupGuideSeen = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: loginLabel
|
||||
text: "Login:"
|
||||
|
||||
Layout.preferredWidth: Math.max(loginLabel.implicitWidth, faLabel.implicitWidth, passLabel.implicitWidth)
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "name/pass error"
|
||||
enabled: user !== undefined //&& user.isLoginRequested && !user.isLogin2FARequested && !user.isLogin2PasswordProvided
|
||||
|
||||
onClicked: {
|
||||
root.backend.loginUsernamePasswordError("")
|
||||
user.resetLoginRequests()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "free user error"
|
||||
enabled: user !== undefined //&& user.isLoginRequested
|
||||
onClicked: {
|
||||
root.backend.loginFreeUserError()
|
||||
user.resetLoginRequests()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "connection error"
|
||||
enabled: user !== undefined //&& user.isLoginRequested
|
||||
onClicked: {
|
||||
root.backend.loginConnectionError("")
|
||||
user.resetLoginRequests()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: faLabel
|
||||
text: "2FA:"
|
||||
|
||||
Layout.preferredWidth: Math.max(loginLabel.implicitWidth, faLabel.implicitWidth, passLabel.implicitWidth)
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "request"
|
||||
|
||||
enabled: user !== undefined //&& user.isLoginRequested && !user.isLogin2FARequested && !user.isLogin2PasswordRequested
|
||||
onClicked: {
|
||||
root.backend.login2FARequested(user.username)
|
||||
user.isLogin2FARequested = true
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "error"
|
||||
|
||||
enabled: user !== undefined //&& user.isLogin2FAProvided && !(user.isLogin2PasswordRequested && !user.isLogin2PasswordProvided)
|
||||
onClicked: {
|
||||
root.backend.login2FAError("")
|
||||
user.isLogin2FAProvided = false
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "Abort"
|
||||
|
||||
enabled: user !== undefined //&& user.isLogin2FAProvided && !(user.isLogin2PasswordRequested && !user.isLogin2PasswordProvided)
|
||||
onClicked: {
|
||||
root.backend.login2FAErrorAbort("")
|
||||
user.resetLoginRequests()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: passLabel
|
||||
text: "2 Password:"
|
||||
|
||||
Layout.preferredWidth: Math.max(loginLabel.implicitWidth, faLabel.implicitWidth, passLabel.implicitWidth)
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "request"
|
||||
|
||||
enabled: user !== undefined //&& user.isLoginRequested && !user.isLogin2PasswordRequested && !(user.isLogin2FARequested && !user.isLogin2FAProvided)
|
||||
onClicked: {
|
||||
root.backend.login2PasswordRequested("")
|
||||
user.isLogin2PasswordRequested = true
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "error"
|
||||
|
||||
enabled: user !== undefined //&& user.isLogin2PasswordProvided && !(user.isLogin2FARequested && !user.isLogin2FAProvided)
|
||||
onClicked: {
|
||||
root.backend.login2PasswordError("")
|
||||
|
||||
user.isLogin2PasswordProvided = false
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "Abort"
|
||||
|
||||
enabled: user !== undefined //&& user.isLogin2PasswordProvided && !(user.isLogin2FARequested && !user.isLogin2FAProvided)
|
||||
onClicked: {
|
||||
root.backend.login2PasswordErrorAbort("")
|
||||
user.resetLoginRequests()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "Login Finished"
|
||||
|
||||
onClicked: {
|
||||
root.backend.loginFinished(0+loginFinishedIndex.text)
|
||||
user.resetLoginRequests()
|
||||
}
|
||||
}
|
||||
TextField {
|
||||
id: loginFinishedIndex
|
||||
colorScheme: root.colorScheme
|
||||
label: "Index:"
|
||||
text: root.userIndex
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "Already logged in"
|
||||
|
||||
onClicked: {
|
||||
root.backend.loginAlreadyLoggedIn(0+loginAlreadyLoggedInIndex.text)
|
||||
user.resetLoginRequests()
|
||||
}
|
||||
}
|
||||
TextField {
|
||||
id: loginAlreadyLoggedInIndex
|
||||
colorScheme: root.colorScheme
|
||||
label: "Index:"
|
||||
text: root.userIndex
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
TextField {
|
||||
colorScheme: root.colorScheme
|
||||
label: "used:"
|
||||
text: user && user.usedBytes ? user.usedBytes : 0
|
||||
onEditingFinished: {
|
||||
user.usedBytes = parseFloat(text)
|
||||
}
|
||||
implicitWidth: 200
|
||||
}
|
||||
TextField {
|
||||
colorScheme: root.colorScheme
|
||||
label: "total:"
|
||||
text: user && user.totalBytes ? user.totalBytes : 0
|
||||
onEditingFinished: {
|
||||
user.totalBytes = parseFloat(text)
|
||||
}
|
||||
implicitWidth: 200
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "Split mode"}
|
||||
Toggle { colorScheme: root.colorScheme; checked: user ? user.splitMode : false; onClicked: {user.splitMode = !user.splitMode}}
|
||||
Button { colorScheme: root.colorScheme; text: "Toggle Finished"; onClicked: {user.toggleSplitModeFinished()}}
|
||||
}
|
||||
|
||||
TextArea { // TODO: this is causing binding loop on imlicitWidth
|
||||
colorScheme: root.colorScheme
|
||||
text: user && user.addresses ? user.addresses.join("\n") : "user@protonmail.com"
|
||||
Layout.fillWidth: true
|
||||
|
||||
onEditingFinished: {
|
||||
user.addresses = text.split("\n")
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
102
internal/frontend/qt6/qml/BridgeTest/UserList.qml
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property ColorScheme colorScheme
|
||||
property var backend
|
||||
|
||||
property alias currentIndex: usersListView.currentIndex
|
||||
ListView {
|
||||
id: usersListView
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 200
|
||||
|
||||
model: backend.usersTest
|
||||
highlightFollowsCurrentItem: true
|
||||
|
||||
delegate: Item {
|
||||
|
||||
implicitHeight: children[0].implicitHeight + anchors.topMargin + anchors.bottomMargin
|
||||
implicitWidth: children[0].implicitWidth + anchors.leftMargin + anchors.rightMargin
|
||||
|
||||
width: usersListView.width
|
||||
|
||||
anchors.margins: 10
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: modelData.username
|
||||
anchors.margins: 10
|
||||
anchors.fill: parent
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
usersListView.currentIndex = index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
highlight: Rectangle {
|
||||
color: root.colorScheme.interaction_default_active
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
|
||||
text: "+"
|
||||
|
||||
onClicked: {
|
||||
var newUserObject = backend.userComponent.createObject(backend)
|
||||
newUserObject.username = backend.loginUser.username.length > 0 ? backend.loginUser.username : "test@protonmail.com"
|
||||
newUserObject.loggedIn = true
|
||||
newUserObject.setupGuideSeen = true // backend.loginUser.setupGuideSeen
|
||||
|
||||
backend.loginUser.username = ""
|
||||
backend.loginUser.loggedIn = false
|
||||
backend.loginUser.setupGuideSeen = false
|
||||
|
||||
backend.users.append( { object: newUserObject } )
|
||||
}
|
||||
}
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "-"
|
||||
|
||||
enabled: usersListView.currentIndex != 0
|
||||
|
||||
onClicked: {
|
||||
// var userObject = backend.users.get(usersListView.currentIndex - 1)
|
||||
backend.users.remove(usersListView.currentIndex - 1)
|
||||
// userObject.deleteLater()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
internal/frontend/qt6/qml/BridgeTest/UserModel.qml
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml.Models 2.12
|
||||
|
||||
ListModel {
|
||||
// overriding get method to ignore any role and return directly object itself
|
||||
function get(row) {
|
||||
if (row < 0 || row >= count) {
|
||||
return undefined
|
||||
}
|
||||
return data(index(row, 0), Qt.DisplayRole)
|
||||
}
|
||||
}
|
||||
982
internal/frontend/qt6/qml/Bridge_test.qml
Normal file
@ -0,0 +1,982 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Window 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
|
||||
import QtQml.Models 2.12
|
||||
|
||||
import Qt.labs.platform 1.1
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
import "./BridgeTest"
|
||||
import BridgePreview 1.0
|
||||
|
||||
import Notifications 1.0
|
||||
|
||||
Window {
|
||||
id: root
|
||||
|
||||
x: 10
|
||||
y: 10
|
||||
width: 800
|
||||
height: 800
|
||||
|
||||
property ColorScheme colorScheme: ProtonStyle.darkStyle
|
||||
|
||||
flags : Qt.Window | Qt.Dialog
|
||||
visible : true
|
||||
title : "Bridge Test GUI"
|
||||
|
||||
// This is needed because on MacOS if first window shown is not transparent -
|
||||
// all other windows of application will not have transparent background (black
|
||||
// instead of transparency). In our case that mean that if BridgeTest will be
|
||||
// shown before StatusWindow - StatusWindow will not have transparent corners.
|
||||
color: "transparent"
|
||||
|
||||
function getCursorPos() {
|
||||
return BridgePreview.getCursorPos()
|
||||
}
|
||||
|
||||
function restart() {
|
||||
root.quit()
|
||||
console.log("Restarting....")
|
||||
root.openBridge()
|
||||
}
|
||||
|
||||
function openBridge() {
|
||||
bridge = bridgeComponent.createObject()
|
||||
var showSetupGuide = false
|
||||
if (showSetupGuide) {
|
||||
var newUserObject = root.userComponent.createObject(root)
|
||||
newUserObject.username = "LerooooyJenkins@protonmail.com"
|
||||
newUserObject.loggedIn = true
|
||||
newUserObject.setupGuideSeen = false
|
||||
root.users.append( { object: newUserObject } )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function quit() {
|
||||
if (bridge !== undefined && bridge !== null) {
|
||||
bridge.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
function guiReady() {
|
||||
console.log("Gui Ready")
|
||||
}
|
||||
|
||||
function _log(msg, color) {
|
||||
logTextArea.text += "<p style='color: " + color + ";'>" + msg + "</p>"
|
||||
logTextArea.text += "\n"
|
||||
}
|
||||
|
||||
function log(msg) {
|
||||
console.log(msg)
|
||||
_log(msg, root.colorScheme.signal_info)
|
||||
}
|
||||
|
||||
function error(msg) {
|
||||
console.error(msg)
|
||||
_log(msg, root.colorScheme.signal_danger)
|
||||
}
|
||||
|
||||
// No user object should be put in this list until a successful login
|
||||
property var users: UserModel {
|
||||
id: _users
|
||||
|
||||
onRowsInserted: {
|
||||
for (var i = first; i <= last; i++) {
|
||||
_usersTest.insert(i + 1, { object: get(i) } )
|
||||
}
|
||||
}
|
||||
|
||||
onRowsRemoved: {
|
||||
_usersTest.remove(first + 1, first - last + 1)
|
||||
}
|
||||
|
||||
onRowsMoved: {
|
||||
_usersTest.move(start + 1, row + 1, end - start + 1)
|
||||
}
|
||||
|
||||
onDataChanged: {
|
||||
for (var i = topLeft.row; i <= bottomRight.row; i++) {
|
||||
_usersTest.set(i + 1, { object: get(i) } )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this list is used on test gui: it contains same users list as users above + fake user to represent login request of new user on pos 0
|
||||
property var usersTest: UserModel {
|
||||
id: _usersTest
|
||||
}
|
||||
|
||||
property var userComponent: Component {
|
||||
id: _userComponent
|
||||
|
||||
QtObject {
|
||||
property string username: ""
|
||||
property bool loggedIn: false
|
||||
property bool splitMode: false
|
||||
|
||||
property bool setupGuideSeen: true
|
||||
|
||||
property var usedBytes: 5350*1024*1024
|
||||
property var totalBytes: 20*1024*1024*1024
|
||||
property string avatarText: "jd"
|
||||
|
||||
property string password: "SMj975NnEYYsqu55GGmlpv"
|
||||
property var addresses: [
|
||||
"jaanedoe@protonmail.com",
|
||||
"jane@pm.me",
|
||||
"jdoe@pm.me"
|
||||
]
|
||||
|
||||
signal loginUsernamePasswordError()
|
||||
signal loginFreeUserError()
|
||||
signal loginConnectionError()
|
||||
signal login2FARequested()
|
||||
signal login2FAError()
|
||||
signal login2FAErrorAbort()
|
||||
signal login2PasswordRequested()
|
||||
signal login2PasswordError()
|
||||
signal login2PasswordErrorAbort()
|
||||
|
||||
// Test purpose only:
|
||||
property bool isFakeUser: this === root.loginUser
|
||||
|
||||
function userSignal(msg) {
|
||||
if (isFakeUser) {
|
||||
return
|
||||
}
|
||||
|
||||
root.log("<- User (" + username + "): " + msg)
|
||||
}
|
||||
|
||||
function toggleSplitMode(makeActive) {
|
||||
userSignal("toggle split mode "+makeActive)
|
||||
}
|
||||
signal toggleSplitModeFinished()
|
||||
|
||||
function configureAppleMail(address){
|
||||
userSignal("confugure apple mail "+address)
|
||||
}
|
||||
|
||||
function logout(){
|
||||
userSignal("logout")
|
||||
loggedIn = false
|
||||
}
|
||||
function remove(){
|
||||
console.log("remove this", users.count)
|
||||
for (var i=0; i<users.count; i++) {
|
||||
if (users.get(i) === this) {
|
||||
users.remove(i,1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onLoginUsernamePasswordError: {
|
||||
userSignal("loginUsernamePasswordError")
|
||||
}
|
||||
onLoginFreeUserError: {
|
||||
userSignal("loginFreeUserError")
|
||||
}
|
||||
onLoginConnectionError: {
|
||||
userSignal("loginConnectionError")
|
||||
}
|
||||
onLogin2FARequested: {
|
||||
userSignal("login2FARequested")
|
||||
}
|
||||
onLogin2FAError: {
|
||||
userSignal("login2FAError")
|
||||
}
|
||||
onLogin2FAErrorAbort: {
|
||||
userSignal("login2FAErrorAbort")
|
||||
}
|
||||
onLogin2PasswordRequested: {
|
||||
userSignal("login2PasswordRequested")
|
||||
}
|
||||
onLogin2PasswordError: {
|
||||
userSignal("login2PasswordError")
|
||||
}
|
||||
onLogin2PasswordErrorAbort: {
|
||||
userSignal("login2PasswordErrorAbort")
|
||||
}
|
||||
|
||||
function resetLoginRequests() {
|
||||
isLoginRequested = false
|
||||
isLogin2FARequested = false
|
||||
isLogin2FAProvided = false
|
||||
isLogin2PasswordRequested = false
|
||||
isLogin2PasswordProvided = false
|
||||
}
|
||||
|
||||
property bool isLoginRequested: false
|
||||
|
||||
property bool isLogin2FARequested: false
|
||||
property bool isLogin2FAProvided: false
|
||||
|
||||
property bool isLogin2PasswordRequested: false
|
||||
property bool isLogin2PasswordProvided: false
|
||||
}
|
||||
}
|
||||
|
||||
// this it fake user used only for representing first login request
|
||||
property var loginUser
|
||||
Component.onCompleted: {
|
||||
var newLoginUser = _userComponent.createObject()
|
||||
root.loginUser = newLoginUser
|
||||
root.loginUser.setupGuideSeen = false
|
||||
_usersTest.append({object: newLoginUser})
|
||||
|
||||
newLoginUser.loginUsernamePasswordError.connect(root.loginUsernamePasswordError)
|
||||
newLoginUser.loginFreeUserError.connect(root.loginFreeUserError)
|
||||
newLoginUser.loginConnectionError.connect(root.loginConnectionError)
|
||||
newLoginUser.login2FARequested.connect(root.login2FARequested)
|
||||
newLoginUser.login2FAError.connect(root.login2FAError)
|
||||
newLoginUser.login2FAErrorAbort.connect(root.login2FAErrorAbort)
|
||||
newLoginUser.login2PasswordRequested.connect(root.login2PasswordRequested)
|
||||
newLoginUser.login2PasswordError.connect(root.login2PasswordError)
|
||||
newLoginUser.login2PasswordErrorAbort.connect(root.login2PasswordErrorAbort)
|
||||
|
||||
|
||||
// add one user on start
|
||||
var hasUserOnStart = false
|
||||
if (hasUserOnStart) {
|
||||
var newUserObject = root.userComponent.createObject(root)
|
||||
newUserObject.username = "LerooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooyJenkins@protonmail.com"
|
||||
newUserObject.loggedIn = true
|
||||
newUserObject.setupGuideSeen = true
|
||||
root.users.append( { object: newUserObject } )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TabBar {
|
||||
id: tabBar
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
TabButton {
|
||||
text: "Global settings"
|
||||
}
|
||||
|
||||
TabButton {
|
||||
text: "User control"
|
||||
}
|
||||
|
||||
TabButton {
|
||||
text: "Notifications"
|
||||
}
|
||||
|
||||
TabButton {
|
||||
text: "Log"
|
||||
}
|
||||
|
||||
TabButton {
|
||||
text: "Settings signals"
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: root.colorScheme.background_norm
|
||||
|
||||
anchors.top: tabBar.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
implicitHeight: children[0].contentHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].contentWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
StackLayout {
|
||||
anchors.fill: parent
|
||||
currentIndex: tabBar.currentIndex
|
||||
anchors.margins: 10
|
||||
|
||||
RowLayout {
|
||||
id: globalTab
|
||||
spacing : 5
|
||||
|
||||
ColumnLayout {
|
||||
spacing : 5
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: "Global settings"
|
||||
}
|
||||
|
||||
ButtonGroup {
|
||||
id: styleRadioGroup
|
||||
}
|
||||
|
||||
RadioButton {
|
||||
colorScheme: root.colorScheme
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: "Light UI"
|
||||
checked: ProtonStyle.currentStyle === ProtonStyle.lightStyle
|
||||
ButtonGroup.group: styleRadioGroup
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked && ProtonStyle.currentStyle !== ProtonStyle.lightStyle) {
|
||||
root.colorSchemeName = "light"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RadioButton {
|
||||
colorScheme: root.colorScheme
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: "Dark UI"
|
||||
checked: ProtonStyle.currentStyle === ProtonStyle.darkStyle
|
||||
ButtonGroup.group: styleRadioGroup
|
||||
|
||||
onCheckedChanged: {
|
||||
if (checked && ProtonStyle.currentStyle !== ProtonStyle.darkStyle) {
|
||||
root.colorSchemeName = "dark"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: showOnStartupCheckbox
|
||||
colorScheme: root.colorScheme
|
||||
text: "Show on startup"
|
||||
checked: root.showOnStartup
|
||||
onCheckedChanged: {
|
||||
root.showOnStartup = checked
|
||||
}
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: showSplashScreen
|
||||
colorScheme: root.colorScheme
|
||||
text: "Show splash screen"
|
||||
checked: root.showSplashScreen
|
||||
onCheckedChanged: {
|
||||
root.showSplashScreen = checked
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
//Layout.fillWidth: true
|
||||
|
||||
text: "Open Bridge"
|
||||
enabled: bridge === undefined || bridge === null
|
||||
onClicked: root.openBridge()
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
//Layout.fillWidth: true
|
||||
|
||||
text: "Close Bridge"
|
||||
enabled: bridge !== undefined && bridge !== null
|
||||
onClicked: {
|
||||
bridge.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing : 5
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: "Notifications"
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "Notify: danger"
|
||||
enabled: bridge !== undefined && bridge !== null
|
||||
onClicked: {
|
||||
bridge.mainWindow.notifyOnlyPaidUsers()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "Notify: warning"
|
||||
enabled: bridge !== undefined && bridge !== null
|
||||
onClicked: {
|
||||
bridge.mainWindow.notifyUpdateManually()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: "Notify: success"
|
||||
enabled: bridge !== undefined && bridge !== null
|
||||
onClicked: {
|
||||
bridge.mainWindow.notifyUserAdded()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: usersTab
|
||||
UserList {
|
||||
id: usersListView
|
||||
Layout.fillHeight: true
|
||||
colorScheme: root.colorScheme
|
||||
backend: root
|
||||
}
|
||||
|
||||
UserControl {
|
||||
colorScheme: root.colorScheme
|
||||
backend: root
|
||||
user: ((root.usersTest.count > usersListView.currentIndex) && usersListView.currentIndex != -1) ? root.usersTest.get(usersListView.currentIndex) : undefined
|
||||
userIndex: usersListView.currentIndex - 1 // -1 because 0 index is fake user
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: notificationsTab
|
||||
spacing: 5
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 5
|
||||
|
||||
Switch {
|
||||
text: "Internet connection"
|
||||
colorScheme: root.colorScheme
|
||||
checked: true
|
||||
onCheckedChanged: {
|
||||
checked ? root.internetOn() : root.internetOff()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Update manual ready"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.updateManualReady("3.14.1592")
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Update manual done"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.updateManualRestartNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Update manual error"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.updateManualError()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Update force"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.updateForce("3.14.1592")
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Update force error"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.updateForceError()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Update silent done"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.updateSilentRestartNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Update silent error"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.updateSilentError()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Update is latest version"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.updateIsLatestVersion()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Bug report send OK"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.reportBugFinished()
|
||||
root.bugReportSendSuccess()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 5
|
||||
|
||||
Button {
|
||||
text: "Bug report send error"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.reportBugFinished()
|
||||
root.bugReportSendError()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Cache anavailable"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.cacheUnavailable()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Cache can't move"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.cacheCantMove()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Cache location change success"
|
||||
onClicked: {
|
||||
root.cacheLocationChangeSuccess()
|
||||
}
|
||||
colorScheme: root.colorScheme
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Disk full"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.diskFull()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "No keychain"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.notifyHasNoKeychain()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Rebuild keychain"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.notifyRebuildKeychain()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Address changed"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.addressChanged("p@v.el")
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Address changed + Logout"
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
root.addressChangedLogout("p@v.el")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: logTextArea
|
||||
colorScheme: root.colorScheme
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
Layout.preferredWidth: 400
|
||||
Layout.preferredHeight: 200
|
||||
|
||||
textFormat: TextEdit.RichText
|
||||
//readOnly: true
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: settingsTab
|
||||
ColumnLayout {
|
||||
RowLayout {
|
||||
Label {colorScheme : root.colorScheme ; text : "GOOS : "}
|
||||
Button {colorScheme : root.colorScheme ; text : "Linux" ; onClicked : root.goos = "linux" ; enabled: root.goos != "linux"}
|
||||
Button {colorScheme : root.colorScheme ; text : "Windows" ; onClicked : root.goos = "windows" ; enabled: root.goos != "windows"}
|
||||
Button {colorScheme : root.colorScheme ; text : "macOS" ; onClicked : root.goos = "darwin" ; enabled: root.goos != "darwin"}
|
||||
}
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "Automatic updates:"}
|
||||
Toggle {colorScheme: root.colorScheme; checked: root.isAutomaticUpdateOn; onClicked: root.isAutomaticUpdateOn = !root.isAutomaticUpdateOn}
|
||||
}
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "Autostart:"}
|
||||
Toggle {colorScheme: root.colorScheme; checked: root.isAutostartOn; onClicked: root.isAutostartOn = !root.isAutostartOn}
|
||||
Button {colorScheme: root.colorScheme; text: "Toggle finished"; onClicked: root.toggleAutostartFinished()}
|
||||
}
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "Beta:"}
|
||||
Toggle {colorScheme: root.colorScheme; checked: root.isBetaEnabled; onClicked: root.isBetaEnabled = !root.isBetaEnabled}
|
||||
}
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "DoH:"}
|
||||
Toggle {colorScheme: root.colorScheme; checked: root.isDoHEnabled; onClicked: root.isDoHEnabled = !root.isDoHEnabled}
|
||||
}
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "All Mail disabled:"}
|
||||
Toggle {colorScheme: root.colorScheme; checked: root.isAllMailVisible; onClicked: root.isAllMailVisible = !root.isAllMailVisible}
|
||||
}
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "Ports:"}
|
||||
TextField {
|
||||
colorScheme:root.colorScheme
|
||||
label: "IMAP"
|
||||
text: root.portIMAP
|
||||
onEditingFinished: root.portIMAP = this.text*1
|
||||
validator: IntValidator {bottom: 1; top: 65536}
|
||||
}
|
||||
TextField {
|
||||
colorScheme:root.colorScheme
|
||||
label: "SMTP"
|
||||
text: root.portSMTP
|
||||
onEditingFinished: root.portSMTP = this.text*1
|
||||
validator: IntValidator {bottom: 1; top: 65536}
|
||||
}
|
||||
Button {colorScheme: root.colorScheme; text: "Change finished"; onClicked: root.changePortFinished()}
|
||||
}
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "SMTP using SSL:"}
|
||||
Toggle {colorScheme: root.colorScheme; checked: root.useSSLforSMTP; onClicked: root.useSSLforSMTP = !root.useSSLforSMTP}
|
||||
}
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "Local cache:"}
|
||||
Toggle {colorScheme: root.colorScheme; checked: root.isDiskCacheEnabled; onClicked: root.isDiskCacheEnabled = !root.isDiskCacheEnabled}
|
||||
TextField {
|
||||
colorScheme:root.colorScheme
|
||||
label: "Path"
|
||||
text: root.diskCachePath.toString().replace("file://", "")
|
||||
implicitWidth: 160
|
||||
onEditingFinished: {
|
||||
root.diskCachePath = Qt.resolvedUrl("file://"+text)
|
||||
}
|
||||
}
|
||||
Button {colorScheme: root.colorScheme; text: "Change finished"; onClicked: root.changeLocalCacheFinished()}
|
||||
}
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "Reset:"}
|
||||
Button {colorScheme: root.colorScheme; text: "Finished"; onClicked: root.resetFinished()}
|
||||
}
|
||||
RowLayout {
|
||||
Label {colorScheme: root.colorScheme; text: "Check update:"}
|
||||
Button {colorScheme: root.colorScheme; text: "Finished"; onClicked: root.checkUpdatesFinished()}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property Bridge bridge
|
||||
|
||||
property string goos: "darwin"
|
||||
|
||||
property bool showOnStartup: true // this actually needs to be false, but since we use Bridge_test for testing purpose - lets default this to true just for convenience
|
||||
property bool dockIconVisible: false
|
||||
|
||||
// this signals are used only when trying to login with new user (i.e. not in users model)
|
||||
signal loginUsernamePasswordError(string errorMsg)
|
||||
signal loginFreeUserError()
|
||||
signal loginConnectionError(string errorMsg)
|
||||
signal login2FARequested(string username)
|
||||
signal login2FAError(string errorMsg)
|
||||
signal login2FAErrorAbort(string errorMsg)
|
||||
signal login2PasswordRequested()
|
||||
signal login2PasswordError(string errorMsg)
|
||||
signal login2PasswordErrorAbort(string errorMsg)
|
||||
signal loginFinished(int index)
|
||||
signal loginAlreadyLoggedIn(int index)
|
||||
|
||||
signal internetOff()
|
||||
signal internetOn()
|
||||
|
||||
signal updateManualReady(var version)
|
||||
signal updateManualRestartNeeded()
|
||||
signal updateManualError()
|
||||
signal updateForce(var version)
|
||||
signal updateForceError()
|
||||
signal updateSilentRestartNeeded()
|
||||
signal updateSilentError()
|
||||
signal updateIsLatestVersion()
|
||||
function checkUpdates(){
|
||||
console.log("check updates")
|
||||
}
|
||||
signal checkUpdatesFinished()
|
||||
function installUpdate() {
|
||||
console.log("manuall install update triggered")
|
||||
}
|
||||
|
||||
|
||||
property bool isDiskCacheEnabled: true
|
||||
// Qt.resolvedUrl("file:///C:/Users/user/AppData/Roaming/protonmail/bridge/cache/c11/messages")
|
||||
property url diskCachePath: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
|
||||
signal cacheUnavailable()
|
||||
signal cacheCantMove()
|
||||
signal cacheLocationChangeSuccess()
|
||||
signal diskFull()
|
||||
function changeLocalCache(enableDiskCache, diskCachePath) {
|
||||
console.debug("-> disk cache", enableDiskCache, diskCachePath)
|
||||
}
|
||||
signal changeLocalCacheFinished()
|
||||
|
||||
|
||||
// Settings
|
||||
property bool isAutomaticUpdateOn : true
|
||||
function toggleAutomaticUpdate(makeItActive) {
|
||||
console.debug("-> silent updates", makeItActive, root.isAutomaticUpdateOn)
|
||||
var callback = function () {
|
||||
root.isAutomaticUpdateOn = makeItActive;
|
||||
console.debug("-> CHANGED silent updates", makeItActive, root.isAutomaticUpdateOn)
|
||||
}
|
||||
atimer.onTriggered.connect(callback)
|
||||
atimer.restart()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: atimer
|
||||
interval: 2000
|
||||
running: false
|
||||
repeat: false
|
||||
}
|
||||
|
||||
property bool isAutostartOn : true // Example of settings with loading state
|
||||
function toggleAutostart(makeItActive) {
|
||||
console.debug("-> autostart", makeItActive, root.isAutostartOn)
|
||||
}
|
||||
signal toggleAutostartFinished()
|
||||
|
||||
property bool isBetaEnabled : false
|
||||
function toggleBeta(makeItActive){
|
||||
console.debug("-> beta", makeItActive, root.isBetaEnabled)
|
||||
root.isBetaEnabled = makeItActive
|
||||
}
|
||||
|
||||
property bool isDoHEnabled : true
|
||||
function toggleDoH(makeItActive){
|
||||
console.debug("-> DoH", makeItActive, root.isDoHEnabled)
|
||||
root.isDoHEnabled = makeItActive
|
||||
}
|
||||
|
||||
property bool isAllMailVisible : true
|
||||
function changeIsAllMailVisible(isVisible){
|
||||
console.debug("-> All Mail Visible", isVisible, root.isAllMailVisible)
|
||||
root.isAllMailVisible = isVisible
|
||||
}
|
||||
|
||||
|
||||
property bool useSSLforSMTP: false
|
||||
function toggleUseSSLforSMTP(makeItActive){
|
||||
console.debug("-> SMTP SSL", makeItActive, root.useSSLforSMTP)
|
||||
}
|
||||
signal toggleUseSSLFinished()
|
||||
|
||||
property string hostname: "127.0.0.1"
|
||||
property int portIMAP: 1143
|
||||
property int portSMTP: 1025
|
||||
function changePorts(imapPort, smtpPort){
|
||||
console.debug("-> ports", imapPort, smtpPort)
|
||||
}
|
||||
function isPortFree(port){
|
||||
if (port == portIMAP) return false
|
||||
if (port == portSMTP) return false
|
||||
if (port == 12345) return false
|
||||
return true
|
||||
}
|
||||
signal changePortFinished()
|
||||
signal portIssueIMAP()
|
||||
signal portIssueSMTP()
|
||||
|
||||
function triggerReset() {
|
||||
console.debug("-> trigger reset")
|
||||
}
|
||||
signal resetFinished()
|
||||
|
||||
property string version: "2.0.X-BridePreview"
|
||||
property url logsPath: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
|
||||
property url licensePath: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
|
||||
property url releaseNotesLink: Qt.resolvedUrl("https://protonmail.com/download/bridge/early_releases.html")
|
||||
property url dependencyLicensesLink: Qt.resolvedUrl("https://github.com/ProtonMail/proton-bridge/v2/blob/master/COPYING_NOTES.md#dependencies")
|
||||
property url landingPageLink: Qt.resolvedUrl("https://protonmail.com/bridge")
|
||||
|
||||
property string colorSchemeName: "light"
|
||||
function changeColorScheme(newScheme){
|
||||
root.colorSchemeName = newScheme
|
||||
}
|
||||
|
||||
|
||||
property string currentEmailClient: "" // "Apple Mail 14.0"
|
||||
function updateCurrentMailClient(){
|
||||
currentEmailClient = "Apple Mail 14.0"
|
||||
}
|
||||
|
||||
function reportBug(description,address,emailClient,includeLogs){
|
||||
console.log("report bug")
|
||||
console.log(" description",description)
|
||||
console.log(" address",address)
|
||||
console.log(" emailClient",emailClient)
|
||||
console.log(" includeLogs",includeLogs)
|
||||
}
|
||||
signal reportBugFinished()
|
||||
signal bugReportSendSuccess()
|
||||
signal bugReportSendError()
|
||||
|
||||
property var availableKeychain: ["gnome-keyring", "pass", "macos-keychain", "windows-credentials"]
|
||||
property string currentKeychain: availableKeychain[0]
|
||||
function changeKeychain(wantedKeychain){
|
||||
console.log("Changing keychain from", root.currentKeychain, "to", wantedKeychain)
|
||||
root.currentKeychain = wantedKeychain
|
||||
root.changeKeychainFinished()
|
||||
}
|
||||
signal changeKeychainFinished()
|
||||
signal notifyHasNoKeychain()
|
||||
signal notifyRebuildKeychain()
|
||||
|
||||
signal noActiveKeyForRecipient(string email)
|
||||
signal showMainWindow()
|
||||
|
||||
signal addressChanged(string address)
|
||||
signal addressChangedLogout(string address)
|
||||
signal userDisconnected(string username)
|
||||
signal apiCertIssue()
|
||||
|
||||
property bool showSplashScreen: false
|
||||
|
||||
|
||||
function login(username, password) {
|
||||
root.log("-> login(" + username + ", " + password + ")")
|
||||
|
||||
loginUser.username = username
|
||||
loginUser.isLoginRequested = true
|
||||
}
|
||||
|
||||
function login2FA(username, code) {
|
||||
root.log("-> login2FA(" + username + ", " + code + ")")
|
||||
|
||||
loginUser.isLogin2FAProvided = true
|
||||
}
|
||||
|
||||
function login2Password(username, password) {
|
||||
root.log("-> login2FA(" + username + ", " + password + ")")
|
||||
|
||||
loginUser.isLogin2PasswordProvided = true
|
||||
}
|
||||
|
||||
function loginAbort(username) {
|
||||
root.log("-> loginAbort(" + username + ")")
|
||||
|
||||
loginUser.resetLoginRequests()
|
||||
}
|
||||
|
||||
|
||||
onLoginUsernamePasswordError: {
|
||||
console.debug("<- loginUsernamePasswordError")
|
||||
}
|
||||
onLoginFreeUserError: {
|
||||
console.debug("<- loginFreeUserError")
|
||||
}
|
||||
onLoginConnectionError: {
|
||||
console.debug("<- loginConnectionError")
|
||||
}
|
||||
onLogin2FARequested: {
|
||||
console.debug("<- login2FARequested", username)
|
||||
}
|
||||
onLogin2FAError: {
|
||||
console.debug("<- login2FAError")
|
||||
}
|
||||
onLogin2FAErrorAbort: {
|
||||
console.debug("<- login2FAErrorAbort")
|
||||
}
|
||||
onLogin2PasswordRequested: {
|
||||
console.debug("<- login2PasswordRequested")
|
||||
}
|
||||
onLogin2PasswordError: {
|
||||
console.debug("<- login2PasswordError")
|
||||
}
|
||||
onLogin2PasswordErrorAbort: {
|
||||
console.debug("<- login2PasswordErrorAbort")
|
||||
}
|
||||
onLoginFinished: {
|
||||
console.debug("<- loginFinished", index)
|
||||
}
|
||||
onLoginAlreadyLoggedIn: {
|
||||
console.debug("<- loginAlreadyLoggedIn", index)
|
||||
}
|
||||
|
||||
onInternetOff: {
|
||||
console.debug("<- internetOff")
|
||||
}
|
||||
onInternetOn: {
|
||||
console.debug("<- internetOn")
|
||||
}
|
||||
|
||||
Component {
|
||||
id: bridgeComponent
|
||||
|
||||
Bridge {
|
||||
backend: root
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
onClosing: {
|
||||
Qt.quit()
|
||||
}
|
||||
}
|
||||
192
internal/frontend/qt6/qml/BugReportView.qml
Normal file
@ -0,0 +1,192 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
SettingsView {
|
||||
id: root
|
||||
|
||||
fillHeight: true
|
||||
|
||||
property var selectedAddress
|
||||
|
||||
Label {
|
||||
text: qsTr("Report a problem")
|
||||
colorScheme: root.colorScheme
|
||||
type: Label.Heading
|
||||
}
|
||||
|
||||
|
||||
TextArea {
|
||||
id: description
|
||||
property int _minLength: 150
|
||||
property int _maxLength: 800
|
||||
|
||||
label: qsTr("Description")
|
||||
colorScheme: root.colorScheme
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.minimumHeight: heightForLinesVisible(4)
|
||||
hint: description.text.length + "/" + _maxLength
|
||||
placeholderText: qsTr("Tell us what went wrong or isn't working (min. %1 characters).").arg(_minLength)
|
||||
|
||||
validator: function(text) {
|
||||
if (description.text.length < description._minLength) {
|
||||
return qsTr("Enter a problem description (min. %1 characters).").arg(_minLength)
|
||||
}
|
||||
|
||||
if (description.text.length > description._maxLength) {
|
||||
return qsTr("Enter a problem description (max. %1 characters).").arg(_maxLength)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
// Rise max length error imidiatly while typing
|
||||
if (description.text.length > description._maxLength) {
|
||||
validate()
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.priority: KeyNavigation.BeforeItem
|
||||
KeyNavigation.tab: address
|
||||
|
||||
// set implicitHeight to explicit height because se don't
|
||||
// want TextArea implicitHeight (which is height of all text)
|
||||
// to be considered in SettingsView internal scroll view
|
||||
implicitHeight: height
|
||||
}
|
||||
|
||||
|
||||
TextField {
|
||||
id: address
|
||||
|
||||
label: qsTr("Your contact email")
|
||||
colorScheme: root.colorScheme
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("e.g. jane.doe@protonmail.com")
|
||||
|
||||
validator: function(str) {
|
||||
if (!isValidEmail(str)) {
|
||||
return qsTr("Enter valid email address")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: emailClient
|
||||
|
||||
label: qsTr("Your email client (including version)")
|
||||
colorScheme: root.colorScheme
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("e.g. Apple Mail 14.0")
|
||||
|
||||
validator: function(str) {
|
||||
if (str.length === 0) {
|
||||
return qsTr("Enter an email client name and version")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RowLayout {
|
||||
CheckBox {
|
||||
id: includeLogs
|
||||
text: qsTr("Include my recent logs")
|
||||
colorScheme: root.colorScheme
|
||||
checked: true
|
||||
}
|
||||
Button {
|
||||
Layout.leftMargin: 12
|
||||
text: qsTr("View logs")
|
||||
secondary: true
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: Qt.openUrlExternally(root.backend.logsPath)
|
||||
}
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
text: qsTr("Reports are not end-to-end encrypted, please do not send any sensitive information.")
|
||||
|
||||
readOnly: true
|
||||
|
||||
Layout.fillWidth: true
|
||||
color: root.colorScheme.text_weak
|
||||
font.family: ProtonStyle.font_family
|
||||
font.weight: ProtonStyle.fontWeight_400
|
||||
font.pixelSize: ProtonStyle.caption_font_size
|
||||
font.letterSpacing: ProtonStyle.caption_letter_spacing
|
||||
// No way to set lineHeight: Style.caption_line_height
|
||||
selectionColor: root.colorScheme.interaction_norm
|
||||
selectedTextColor: root.colorScheme.text_invert
|
||||
wrapMode: Text.WordWrap
|
||||
selectByMouse: true
|
||||
}
|
||||
|
||||
Button {
|
||||
id: sendButton
|
||||
text: qsTr("Send")
|
||||
colorScheme: root.colorScheme
|
||||
|
||||
onClicked: {
|
||||
description.validate()
|
||||
address.validate()
|
||||
emailClient.validate()
|
||||
|
||||
if (description.error || address.error || emailClient.error) {
|
||||
return
|
||||
}
|
||||
|
||||
submit()
|
||||
}
|
||||
|
||||
Connections {target: root.backend; onReportBugFinished: sendButton.loading = false }
|
||||
}
|
||||
|
||||
function setDefaultValue() {
|
||||
description.text = ""
|
||||
address.text = root.selectedAddress
|
||||
emailClient.text = root.backend.currentEmailClient
|
||||
includeLogs.checked = true
|
||||
}
|
||||
|
||||
function isValidEmail(text){
|
||||
var reEmail = /^[^@]+@[^@]+\.[A-Za-z]+\s*$/
|
||||
return reEmail.test(text)
|
||||
}
|
||||
|
||||
function submit() {
|
||||
sendButton.loading = true
|
||||
root.backend.reportBug(
|
||||
description.text,
|
||||
address.text,
|
||||
emailClient.text,
|
||||
includeLogs.checked
|
||||
)
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
root.setDefaultValue()
|
||||
}
|
||||
}
|
||||
73
internal/frontend/qt6/qml/Configuration.qml
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property ColorScheme colorScheme
|
||||
property string title
|
||||
property string hostname
|
||||
property string port
|
||||
property string username
|
||||
property string password
|
||||
property string security
|
||||
|
||||
implicitWidth: 304
|
||||
implicitHeight: content.height + 2*root._margin
|
||||
|
||||
color: root.colorScheme.background_norm
|
||||
radius: ProtonStyle.card_radius
|
||||
|
||||
property int _margin: 24
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
width: root.width - 2*root._margin
|
||||
anchors{
|
||||
top: root.top
|
||||
left: root.left
|
||||
leftMargin : root._margin
|
||||
rightMargin : root._margin
|
||||
topMargin : root._margin
|
||||
bottomMargin : root._margin
|
||||
}
|
||||
|
||||
spacing: 12
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: root.title
|
||||
type: Label.Body_semibold
|
||||
}
|
||||
|
||||
Item{}
|
||||
|
||||
ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Hostname") ; value: root.hostname }
|
||||
ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Port") ; value: root.port }
|
||||
ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Username") ; value: root.username }
|
||||
ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Password") ; value: root.password }
|
||||
ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Security") ; value: root.security }
|
||||
}
|
||||
}
|
||||
|
||||
89
internal/frontend/qt6/qml/ConfigurationItem.qml
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
Layout.fillWidth: true
|
||||
|
||||
property var colorScheme
|
||||
property string label
|
||||
property string value
|
||||
|
||||
implicitHeight: children[0].implicitHeight
|
||||
implicitWidth: children[0].implicitWidth
|
||||
|
||||
ColumnLayout {
|
||||
width: root.width
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: root.label
|
||||
type: Label.Body
|
||||
}
|
||||
TextEdit {
|
||||
id: valueText
|
||||
text: root.value
|
||||
color: root.colorScheme.text_weak
|
||||
readOnly: true
|
||||
selectByMouse: true
|
||||
selectByKeyboard: true
|
||||
selectionColor: root.colorScheme.text_weak
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
ColorImage {
|
||||
source: "icons/ic-copy.svg"
|
||||
color: root.colorScheme.text_norm
|
||||
height: root.colorScheme.body_font_size
|
||||
sourceSize.height: root.colorScheme.body_font_size
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked : {
|
||||
valueText.select(0, valueText.length)
|
||||
valueText.copy()
|
||||
valueText.deselect()
|
||||
}
|
||||
onPressed: parent.scale = 0.90
|
||||
onReleased: parent.scale = 1
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: root.colorScheme.border_norm
|
||||
}
|
||||
}
|
||||
}
|
||||
408
internal/frontend/qt6/qml/ContentWrapper.qml
Normal file
@ -0,0 +1,408 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Proton 4.0
|
||||
import Notifications 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property ColorScheme colorScheme
|
||||
|
||||
property var backend
|
||||
property var notifications
|
||||
|
||||
signal showSetupGuide(var user, string address)
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
id: leftBar
|
||||
property ColorScheme colorScheme: root.colorScheme.prominent
|
||||
|
||||
Layout.minimumWidth: 264
|
||||
Layout.maximumWidth: 320
|
||||
Layout.preferredWidth: 320
|
||||
Layout.fillHeight: true
|
||||
|
||||
color: colorScheme.background_norm
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
id:topLeftBar
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: 60
|
||||
Layout.maximumHeight: 60
|
||||
Layout.preferredHeight: 60
|
||||
spacing: 0
|
||||
|
||||
Status {
|
||||
Layout.leftMargin: 16
|
||||
Layout.topMargin: 24
|
||||
Layout.bottomMargin: 17
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
colorScheme: leftBar.colorScheme
|
||||
backend: root.backend
|
||||
notifications: root.notifications
|
||||
|
||||
notificationWhitelist: Notifications.Group.Connection | Notifications.Group.ForceUpdate
|
||||
}
|
||||
|
||||
// just a placeholder
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: leftBar.colorScheme
|
||||
Layout.minimumHeight: 36
|
||||
Layout.maximumHeight: 36
|
||||
Layout.preferredHeight: 36
|
||||
Layout.minimumWidth: 36
|
||||
Layout.maximumWidth: 36
|
||||
Layout.preferredWidth: 36
|
||||
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: 9
|
||||
Layout.rightMargin: 4
|
||||
|
||||
horizontalPadding: 0
|
||||
|
||||
icon.source: "./icons/ic-question-circle.svg"
|
||||
|
||||
onClicked: rightContent.showHelpView()
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: leftBar.colorScheme
|
||||
Layout.minimumHeight: 36
|
||||
Layout.maximumHeight: 36
|
||||
Layout.preferredHeight: 36
|
||||
Layout.minimumWidth: 36
|
||||
Layout.maximumWidth: 36
|
||||
Layout.preferredWidth: 36
|
||||
|
||||
Layout.topMargin: 16
|
||||
Layout.bottomMargin: 9
|
||||
Layout.rightMargin: 16
|
||||
|
||||
horizontalPadding: 0
|
||||
|
||||
icon.source: "./icons/ic-cog-wheel.svg"
|
||||
|
||||
onClicked: rightContent.showGeneralSettings()
|
||||
}
|
||||
}
|
||||
|
||||
Item {implicitHeight:10}
|
||||
|
||||
// Separator line
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: 1
|
||||
Layout.maximumHeight: 1
|
||||
color: leftBar.colorScheme.border_weak
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: accounts
|
||||
|
||||
property var _topBottomMargins: 24
|
||||
property var _leftRightMargins: 16
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: accounts._leftRightMargins
|
||||
Layout.rightMargin: accounts._leftRightMargins
|
||||
Layout.topMargin: accounts._topBottomMargins
|
||||
Layout.bottomMargin: accounts._topBottomMargins
|
||||
|
||||
spacing: 12
|
||||
clip: true
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
header: Rectangle {
|
||||
height: headerLabel.height+16
|
||||
// color: ProtonStyle.transparent
|
||||
Label{
|
||||
colorScheme: leftBar.colorScheme
|
||||
id: headerLabel
|
||||
text: qsTr("Accounts")
|
||||
type: Label.LabelType.Body
|
||||
}
|
||||
}
|
||||
|
||||
highlight: Rectangle {
|
||||
color: leftBar.colorScheme.interaction_default_active
|
||||
radius: ProtonStyle.account_row_radius
|
||||
}
|
||||
|
||||
model: root.backend.users
|
||||
delegate: Item {
|
||||
width: leftBar.width - 2*accounts._leftRightMargins
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
AccountDelegate {
|
||||
id: accountDelegate
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 8
|
||||
anchors.bottomMargin: 8
|
||||
anchors.leftMargin: 12
|
||||
anchors.rightMargin: 12
|
||||
|
||||
colorScheme: leftBar.colorScheme
|
||||
user: root.backend.users.get(index)
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
var user = root.backend.users.get(index)
|
||||
accounts.currentIndex = index
|
||||
if (!user) return
|
||||
if (user.loggedIn) {
|
||||
rightContent.showAccount()
|
||||
} else {
|
||||
signIn.username = user.username
|
||||
rightContent.showSignIn()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Separator
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: 1
|
||||
Layout.maximumHeight: 1
|
||||
color: leftBar.colorScheme.border_weak
|
||||
}
|
||||
|
||||
Item {
|
||||
id: bottomLeftBar
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: 52
|
||||
Layout.maximumHeight: 52
|
||||
Layout.preferredHeight: 52
|
||||
|
||||
Button {
|
||||
colorScheme: leftBar.colorScheme
|
||||
width: 36
|
||||
height: 36
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
|
||||
anchors.leftMargin: 16
|
||||
anchors.topMargin: 7
|
||||
|
||||
horizontalPadding: 0
|
||||
|
||||
icon.source: "./icons/ic-plus.svg"
|
||||
|
||||
onClicked: {
|
||||
signIn.username = ""
|
||||
rightContent.showSignIn()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { // right content background
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
color: colorScheme.background_norm
|
||||
|
||||
StackLayout {
|
||||
id: rightContent
|
||||
anchors.fill: parent
|
||||
|
||||
AccountView { // 0
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
notifications: root.notifications
|
||||
user: {
|
||||
if (accounts.currentIndex < 0) return undefined
|
||||
if (root.backend.users.count == 0) return undefined
|
||||
return root.backend.users.get(accounts.currentIndex)
|
||||
}
|
||||
onShowSignIn: {
|
||||
signIn.username = this.user.username
|
||||
rightContent.showSignIn()
|
||||
}
|
||||
onShowSetupGuide: {
|
||||
root.showSetupGuide(user,address)
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout { // 1 Sign In
|
||||
columns: 2
|
||||
|
||||
Button {
|
||||
id: backButton
|
||||
Layout.leftMargin: 18
|
||||
Layout.topMargin: 10
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: {
|
||||
signIn.abort()
|
||||
rightContent.showAccount()
|
||||
}
|
||||
icon.source: "icons/ic-arrow-left.svg"
|
||||
secondary: true
|
||||
horizontalPadding: 8
|
||||
}
|
||||
|
||||
SignIn {
|
||||
id: signIn
|
||||
Layout.topMargin: 68
|
||||
Layout.leftMargin: 80 - backButton.width - 18
|
||||
Layout.rightMargin: 80
|
||||
Layout.bottomMargin: 68
|
||||
Layout.preferredWidth: 320
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
}
|
||||
}
|
||||
|
||||
GeneralSettings { // 2
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
notifications: root.notifications
|
||||
|
||||
onBack: {
|
||||
rightContent.showAccount()
|
||||
}
|
||||
}
|
||||
|
||||
KeychainSettings { // 3
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
|
||||
onBack: {
|
||||
rightContent.showGeneralSettings()
|
||||
}
|
||||
}
|
||||
|
||||
PortSettings { // 4
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
|
||||
onBack: {
|
||||
rightContent.showGeneralSettings()
|
||||
}
|
||||
}
|
||||
|
||||
SMTPSettings { // 5
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
|
||||
onBack: {
|
||||
rightContent.showGeneralSettings()
|
||||
}
|
||||
}
|
||||
|
||||
LocalCacheSettings { // 6
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
notifications: root.notifications
|
||||
|
||||
onBack: {
|
||||
rightContent.showGeneralSettings()
|
||||
}
|
||||
}
|
||||
|
||||
HelpView { // 7
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
|
||||
onBack: {
|
||||
rightContent.showAccount()
|
||||
}
|
||||
}
|
||||
|
||||
BugReportView { // 8
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
selectedAddress: {
|
||||
if (accounts.currentIndex < 0) return ""
|
||||
if (root.backend.users.count == 0) return ""
|
||||
var user = root.backend.users.get(accounts.currentIndex)
|
||||
if (!user) return ""
|
||||
return user.addresses[0]
|
||||
}
|
||||
|
||||
onBack: {
|
||||
rightContent.showHelpView()
|
||||
}
|
||||
}
|
||||
|
||||
function showAccount(index) {
|
||||
if (index !== undefined && index >= 0){
|
||||
accounts.currentIndex = index
|
||||
}
|
||||
rightContent.currentIndex = 0
|
||||
}
|
||||
|
||||
function showSignIn () { rightContent.currentIndex = 1 }
|
||||
function showGeneralSettings () { rightContent.currentIndex = 2 }
|
||||
function showKeychainSettings () { rightContent.currentIndex = 3 }
|
||||
function showPortSettings () { rightContent.currentIndex = 4 }
|
||||
function showSMTPSettings () { rightContent.currentIndex = 5 }
|
||||
function showLocalCacheSettings () { rightContent.currentIndex = 6 }
|
||||
function showHelpView () { rightContent.currentIndex = 7 }
|
||||
function showBugReport () { rightContent.currentIndex = 8 }
|
||||
|
||||
Connections {
|
||||
target: root.backend
|
||||
|
||||
onLoginFinished: rightContent.showAccount(index)
|
||||
onLoginAlreadyLoggedIn: rightContent.showAccount(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showLocalCacheSettings(){rightContent.showLocalCacheSettings() }
|
||||
function showSettings(){rightContent.showGeneralSettings() }
|
||||
function showHelp(){rightContent.showHelpView() }
|
||||
function showSignIn(username){
|
||||
signIn.username = username
|
||||
rightContent.showSignIn()
|
||||
}
|
||||
}
|
||||
55
internal/frontend/qt6/qml/DebugWrapper.qml
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import "."
|
||||
import "./Proton"
|
||||
|
||||
Rectangle {
|
||||
property var target: parent
|
||||
|
||||
x: target.x
|
||||
y: target.y
|
||||
width: target.width
|
||||
height: target.height
|
||||
|
||||
color: "transparent"
|
||||
border.color: "red"
|
||||
border.width: 1
|
||||
//z: parent.z - 1
|
||||
z: 10000000
|
||||
|
||||
Label {
|
||||
text: parent.width + "x" + parent.height
|
||||
anchors.centerIn: parent
|
||||
color: "black"
|
||||
colorScheme: ProtonStyle.currentStyle
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: target.implicitWidth
|
||||
height: target.implicitHeight
|
||||
|
||||
color: "transparent"
|
||||
border.color: "green"
|
||||
border.width: 1
|
||||
//z: parent.z - 1
|
||||
z: 10000000
|
||||
}
|
||||
}
|
||||
225
internal/frontend/qt6/qml/GeneralSettings.qml
Normal file
@ -0,0 +1,225 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Controls.impl 2.13
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
SettingsView {
|
||||
id: root
|
||||
|
||||
property bool _isAdvancedShown: false
|
||||
property var notifications
|
||||
|
||||
fillHeight: false
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Settings")
|
||||
type: Label.Heading
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: autoUpdate
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Automatic updates")
|
||||
description: qsTr("Bridge will automatically update in the background.")
|
||||
type: SettingsItem.Toggle
|
||||
checked: root.backend.isAutomaticUpdateOn
|
||||
onClicked: root.backend.toggleAutomaticUpdate(!autoUpdate.checked)
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: autostart
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Open on startup")
|
||||
description: qsTr("Bridge will open upon startup.")
|
||||
type: SettingsItem.Toggle
|
||||
checked: root.backend.isAutostartOn
|
||||
onClicked: {
|
||||
autostart.loading = true
|
||||
root.backend.toggleAutostart(!autostart.checked)
|
||||
}
|
||||
Connections{
|
||||
target: root.backend
|
||||
onToggleAutostartFinished: {
|
||||
autostart.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: beta
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Beta access")
|
||||
description: qsTr("Be among the first to try new features.")
|
||||
type: SettingsItem.Toggle
|
||||
checked: root.backend.isBetaEnabled
|
||||
onClicked: {
|
||||
if (!beta.checked) {
|
||||
root.notifications.askEnableBeta()
|
||||
} else {
|
||||
root.backend.toggleBeta(false)
|
||||
}
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
ColorImage {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
source: root._isAdvancedShown ? "icons/ic-chevron-up.svg" : "icons/ic-chevron-down.svg"
|
||||
color: root.colorScheme.interaction_norm
|
||||
height: root.colorScheme.body_font_size
|
||||
sourceSize.height: root.colorScheme.body_font_size
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root._isAdvancedShown = !root._isAdvancedShown
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: advSettLabel
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Advanced settings")
|
||||
color: root.colorScheme.interaction_norm
|
||||
type: Label.Body
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root._isAdvancedShown = !root._isAdvancedShown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: keychains
|
||||
visible: root._isAdvancedShown && root.backend.availableKeychain.length > 1
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Change keychain")
|
||||
description: qsTr("Change which keychain Bridge uses as default")
|
||||
actionText: qsTr("Change")
|
||||
type: SettingsItem.Button
|
||||
checked: root.backend.isDoHEnabled
|
||||
onClicked: root.parent.showKeychainSettings()
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: doh
|
||||
visible: root._isAdvancedShown
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Alternative routing")
|
||||
description: qsTr("If Proton’s servers are blocked in your location, alternative network routing will be used to reach Proton.")
|
||||
type: SettingsItem.Toggle
|
||||
checked: root.backend.isDoHEnabled
|
||||
onClicked: root.backend.toggleDoH(!doh.checked)
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: darkMode
|
||||
visible: root._isAdvancedShown
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Dark mode")
|
||||
description: qsTr("Choose dark color theme.")
|
||||
type: SettingsItem.Toggle
|
||||
checked: root.backend.colorSchemeName == "dark"
|
||||
onClicked: root.backend.changeColorScheme( darkMode.checked ? "light" : "dark")
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: allMail
|
||||
visible: root._isAdvancedShown
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Show All Mail")
|
||||
description: qsTr("Choose to list the All Mail folder in your local client.")
|
||||
type: SettingsItem.Toggle
|
||||
checked: root.backend.isAllMailVisible
|
||||
onClicked: root.notifications.askChangeAllMailVisibility(root.backend.isAllMailVisible)
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: ports
|
||||
visible: root._isAdvancedShown
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Default ports")
|
||||
actionText: qsTr("Change")
|
||||
description: qsTr("Choose which ports are used by default.")
|
||||
type: SettingsItem.Button
|
||||
onClicked: root.parent.showPortSettings()
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: smtp
|
||||
visible: root._isAdvancedShown
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("SMTP connection mode")
|
||||
actionText: qsTr("Change")
|
||||
description: qsTr("Change the protocol Bridge and your client use to connect.")
|
||||
type: SettingsItem.Button
|
||||
onClicked: root.parent.showSMTPSettings()
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: cache
|
||||
visible: root._isAdvancedShown
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Local cache")
|
||||
actionText: qsTr("Configure")
|
||||
description: qsTr("Configure Bridge's local cache.")
|
||||
type: SettingsItem.Button
|
||||
onClicked: root.parent.showLocalCacheSettings()
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: reset
|
||||
visible: root._isAdvancedShown
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Reset Bridge")
|
||||
actionText: qsTr("Reset")
|
||||
description: qsTr("Remove all accounts, clear cached data, and restore the original settings.")
|
||||
type: SettingsItem.Button
|
||||
onClicked: {
|
||||
root.notifications.askResetBridge()
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
116
internal/frontend/qt6/qml/HelpView.qml
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
SettingsView {
|
||||
id: root
|
||||
|
||||
fillHeight: true
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Help")
|
||||
type: Label.Heading
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: setupPage
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Installation and setup")
|
||||
actionText: qsTr("Go to help topics")
|
||||
actionIcon: "./icons/ic-external-link.svg"
|
||||
description: qsTr("Get help setting up your client with our instructions and FAQs.")
|
||||
type: SettingsItem.PrimaryButton
|
||||
onClicked: {Qt.openUrlExternally("https://protonmail.com/support/categories/bridge/")}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: checkUpdates
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Updates")
|
||||
actionText: qsTr("Check now")
|
||||
description: qsTr("Check that you're using the latest version of Bridge. To stay up to date, enable auto-updates in settings.")
|
||||
type: SettingsItem.Button
|
||||
onClicked: {
|
||||
checkUpdates.loading = true
|
||||
root.backend.checkUpdates()
|
||||
}
|
||||
|
||||
Connections {target: root.backend; onCheckUpdatesFinished: checkUpdates.loading = false}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: logs
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Logs")
|
||||
actionText: qsTr("View logs")
|
||||
description: qsTr("Open and review logs to troubleshoot.")
|
||||
type: SettingsItem.Button
|
||||
onClicked: Qt.openUrlExternally(root.backend.logsPath)
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
id: reportBug
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Report a problem")
|
||||
actionText: qsTr("Report a problem")
|
||||
description: qsTr("Something not working as expected? Let us know.")
|
||||
type: SettingsItem.Button
|
||||
onClicked: {
|
||||
root.backend.updateCurrentMailClient()
|
||||
root.parent.showBugReport()
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// fill height so the footer label will be allways attached to the bottom
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
colorScheme: root.colorScheme
|
||||
type: Label.Caption
|
||||
color: root.colorScheme.text_weak
|
||||
textFormat: Text.StyledText
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
text: qsTr("Proton Mail Bridge v%1<br>© 2021 Proton AG<br>%2 %3<br>%4").
|
||||
arg(root.backend.version).
|
||||
arg(link(root.backend.licensePath, qsTr("License"))).
|
||||
arg(link(root.backend.dependencyLicensesLink, qsTr("Dependencies"))).
|
||||
arg(link(root.backend.releaseNotesLink, qsTr("Release notes")))
|
||||
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
116
internal/frontend/qt6/qml/KeychainSettings.qml
Normal file
@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Controls.impl 2.13
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
SettingsView {
|
||||
id: root
|
||||
|
||||
fillHeight: false
|
||||
|
||||
property bool _valuesChanged: keychainSelection.checkedButton && keychainSelection.checkedButton.text != root.backend.currentKeychain
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Default keychain")
|
||||
type: Label.Heading
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Change which keychain Bridge uses as default")
|
||||
type: Label.Body
|
||||
color: root.colorScheme.text_weak
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 16
|
||||
|
||||
ButtonGroup{ id: keychainSelection }
|
||||
|
||||
Repeater {
|
||||
model: root.backend.availableKeychain
|
||||
|
||||
RadioButton {
|
||||
colorScheme: root.colorScheme
|
||||
ButtonGroup.group: keychainSelection
|
||||
text: modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: root.colorScheme.border_weak
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
|
||||
Button {
|
||||
id: submitButton
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Save and restart")
|
||||
enabled: root._valuesChanged
|
||||
onClicked: {
|
||||
root.backend.changeKeychain(keychainSelection.checkedButton.text)
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Cancel")
|
||||
onClicked: root.back()
|
||||
secondary: true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.backend
|
||||
|
||||
onChangeKeychainFinished: {
|
||||
submitButton.loading = false
|
||||
root.back()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBack: {
|
||||
root.setDefaultValues()
|
||||
}
|
||||
|
||||
function setDefaultValues(){
|
||||
for (var bi in keychainSelection.buttons){
|
||||
var button = keychainSelection.buttons[bi]
|
||||
if (button.text == root.backend.currentKeychain) {
|
||||
button.checked = true
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: root.setDefaultValues()
|
||||
}
|
||||
149
internal/frontend/qt6/qml/LocalCacheSettings.qml
Normal file
@ -0,0 +1,149 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Controls.impl 2.13
|
||||
import QtQuick.Dialogs 1.1
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
SettingsView {
|
||||
id: root
|
||||
|
||||
fillHeight: false
|
||||
|
||||
property var notifications
|
||||
property bool _diskCacheEnabled: true
|
||||
property url _diskCachePath: pathDialog.shortcuts.home
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Local cache")
|
||||
type: Label.Heading
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Bridge stores your encrypted messages locally to optimize communication with your client.")
|
||||
type: Label.Body
|
||||
color: root.colorScheme.text_weak
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: this.parent.Layout.maximumWidth
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Enable local cache")
|
||||
description: qsTr("Recommended for optimal performance.")
|
||||
type: SettingsItem.Toggle
|
||||
checked: root._diskCacheEnabled
|
||||
onClicked: root._diskCacheEnabled = !root._diskCacheEnabled
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SettingsItem {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Current cache location")
|
||||
actionText: qsTr("Change location")
|
||||
description: root.backend.goos === "windows" ?
|
||||
root._diskCachePath.toString().replace("file:///", "").replace(new RegExp("/", 'g'), "\\") + "\\" :
|
||||
root._diskCachePath.toString().replace("file://", "") + "/"
|
||||
descriptionWrap: Text.WrapAnywhere
|
||||
type: SettingsItem.Button
|
||||
enabled: root._diskCacheEnabled
|
||||
onClicked: {
|
||||
pathDialog.open()
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
FileDialog {
|
||||
id: pathDialog
|
||||
title: qsTr("Select cache location")
|
||||
folder: root._diskCachePath
|
||||
onAccepted: root._diskCachePath = pathDialog.fileUrl
|
||||
selectFolder: true
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
|
||||
Button {
|
||||
id: submitButton
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Save and restart")
|
||||
enabled: (
|
||||
root.backend.diskCachePath != root._diskCachePath ||
|
||||
root.backend.isDiskCacheEnabled != root._diskCacheEnabled
|
||||
)
|
||||
onClicked: {
|
||||
root.submit()
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Cancel")
|
||||
onClicked: root.back()
|
||||
secondary: true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.backend
|
||||
|
||||
onChangeLocalCacheFinished: {
|
||||
submitButton.loading = false
|
||||
root.setDefaultValues()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBack: {
|
||||
root.setDefaultValues()
|
||||
}
|
||||
|
||||
function submit(){
|
||||
if (!root._diskCacheEnabled && root.backend.isDiskCacheEnabled) {
|
||||
root.notifications.askDisableLocalCache()
|
||||
return
|
||||
}
|
||||
|
||||
if (root._diskCacheEnabled && !root.backend.isDiskCacheEnabled) {
|
||||
root.notifications.askEnableLocalCache(root._diskCachePath)
|
||||
return
|
||||
}
|
||||
|
||||
// Not asking, only changing path
|
||||
submitButton.loading = true
|
||||
root.backend.changeLocalCache(root.backend.isDiskCacheEnabled, root._diskCachePath)
|
||||
}
|
||||
|
||||
function setDefaultValues(){
|
||||
root._diskCacheEnabled = root.backend.isDiskCacheEnabled
|
||||
root._diskCachePath = root.backend.diskCachePath
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
root.setDefaultValues()
|
||||
}
|
||||
}
|
||||
212
internal/frontend/qt6/qml/MainWindow.qml
Normal file
@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Window 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Proton 4.0
|
||||
import Notifications 1.0
|
||||
import CppBackend 1.0
|
||||
|
||||
import "tests"
|
||||
|
||||
ApplicationWindow {
|
||||
id: root
|
||||
|
||||
width: 960
|
||||
height: 576
|
||||
|
||||
visible: true
|
||||
|
||||
minimumHeight: contentLayout.implicitHeight
|
||||
minimumWidth: contentLayout.implicitWidth
|
||||
|
||||
colorScheme: ProtonStyle.currentStyle
|
||||
|
||||
|
||||
property var backend
|
||||
property var notifications
|
||||
|
||||
// This is needed because on MacOS if first window shown is not transparent -
|
||||
// all other windows of application will not have transparent background (black
|
||||
// instead of transparency). In our case that mean that if MainWindow will be
|
||||
// shown before StatusWindow - StatusWindow will not have transparent corners.
|
||||
color: "transparent"
|
||||
|
||||
// show Setup Guide on every new user
|
||||
Connections {
|
||||
target: root.backend.users
|
||||
|
||||
onRowsInserted: {
|
||||
// considerring that users are added one-by-one
|
||||
var user = root.backend.users.get(first)
|
||||
|
||||
if (!user.loggedIn) {
|
||||
return
|
||||
}
|
||||
|
||||
if (user.setupGuideSeen) {
|
||||
return
|
||||
}
|
||||
|
||||
root.showSetup(user,user.addresses[0])
|
||||
}
|
||||
|
||||
onRowsAboutToBeRemoved: {
|
||||
for (var i = first; i <= last; i++ ) {
|
||||
var user = root.backend.users.get(i)
|
||||
|
||||
if (setupGuide.user === user) {
|
||||
setupGuide.user = null
|
||||
contentLayout._showSetup = false
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.backend
|
||||
|
||||
onShowMainWindow: {
|
||||
root.showAndRise()
|
||||
}
|
||||
|
||||
onLoginFinished: {
|
||||
console.debug("Login finished", index)
|
||||
}
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
id: contentLayout
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
property bool _showSetup: false
|
||||
currentIndex: {
|
||||
// show welcome when there are no users or only one non-logged-in user is present
|
||||
if (backend.users.count === 0) {
|
||||
return 1
|
||||
}
|
||||
|
||||
var u = backend.users.get(0)
|
||||
|
||||
if (!u) {
|
||||
console.trace()
|
||||
console.log("empty user")
|
||||
return 1
|
||||
}
|
||||
|
||||
if (backend.users.count === 1 && u.loggedIn === false) {
|
||||
return 1
|
||||
}
|
||||
|
||||
if (contentLayout._showSetup) {
|
||||
return 2
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
ContentWrapper { // 0
|
||||
id: contentWrapper
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
notifications: root.notifications
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
onShowSetupGuide: {
|
||||
root.showSetup(user,address)
|
||||
}
|
||||
}
|
||||
|
||||
WelcomeGuide { // 1
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
SetupGuide { // 2
|
||||
id: setupGuide
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
onDismissed: {
|
||||
root.showSetup(null,"")
|
||||
}
|
||||
|
||||
onFinished: {
|
||||
// TODO: Do not close window. Trigger backend to check that
|
||||
// there is a successfully connected client. Then backend
|
||||
// should send another signal to close the setup guide.
|
||||
root.showSetup(null,"")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NotificationPopups {
|
||||
colorScheme: root.colorScheme
|
||||
notifications: root.notifications
|
||||
mainWindow: root
|
||||
backend: root.backend
|
||||
}
|
||||
|
||||
SplashScreen {
|
||||
id: splashScreen
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
}
|
||||
|
||||
function showLocalCacheSettings() { contentWrapper.showLocalCacheSettings() }
|
||||
function showSettings() { contentWrapper.showSettings() }
|
||||
function showHelp() { contentWrapper.showHelp() }
|
||||
|
||||
function showSignIn(username) {
|
||||
if (contentLayout.currentIndex == 1) return
|
||||
contentWrapper.showSignIn(username)
|
||||
}
|
||||
|
||||
function showSetup(user, address) {
|
||||
setupGuide.user = user
|
||||
setupGuide.address = address
|
||||
setupGuide.reset()
|
||||
if (setupGuide.user) {
|
||||
contentLayout._showSetup = true
|
||||
} else {
|
||||
contentLayout._showSetup = false
|
||||
}
|
||||
}
|
||||
|
||||
function showAndRise() {
|
||||
root.show()
|
||||
root.raise()
|
||||
if (!root.active) {
|
||||
root.requestActivate()
|
||||
}
|
||||
}
|
||||
}
|
||||
119
internal/frontend/qt6/qml/NotificationDialog.qml
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Proton 4.0
|
||||
import Notifications 1.0
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
|
||||
property var notification
|
||||
|
||||
shouldShow: notification && notification.active && !notification.dismissed
|
||||
modal: true
|
||||
|
||||
default property alias data: additionalChildrenContainer.children
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
Image {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
sourceSize.width: 64
|
||||
sourceSize.height: 64
|
||||
|
||||
Layout.preferredHeight: 64
|
||||
Layout.preferredWidth: 64
|
||||
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
visible: source != ""
|
||||
|
||||
source: {
|
||||
if (!root.notification) {
|
||||
return ""
|
||||
}
|
||||
|
||||
switch (root.notification.type) {
|
||||
case Notification.NotificationType.Info:
|
||||
return "./icons/ic-info.svg"
|
||||
case Notification.NotificationType.Success:
|
||||
return "./icons/ic-success.svg"
|
||||
case Notification.NotificationType.Warning:
|
||||
case Notification.NotificationType.Danger:
|
||||
return "./icons/ic-alert.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.bottomMargin: 8
|
||||
colorScheme: root.colorScheme
|
||||
text: root.notification.title
|
||||
type: Label.LabelType.Title
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 240
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
colorScheme: root.colorScheme
|
||||
text: root.notification.description
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
type: Label.LabelType.Body
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
|
||||
Item {
|
||||
id: additionalChildrenContainer
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 16
|
||||
|
||||
visible: children.length > 0
|
||||
|
||||
implicitHeight: additionalChildrenContainer.childrenRect.height
|
||||
implicitWidth: additionalChildrenContainer.childrenRect.width
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 8
|
||||
Repeater {
|
||||
model: root.notification.action
|
||||
delegate: Button {
|
||||
Layout.fillWidth: true
|
||||
|
||||
colorScheme: root.colorScheme
|
||||
action: modelData
|
||||
|
||||
secondary: index > 0
|
||||
|
||||
loading: modelData.loading
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
132
internal/frontend/qt6/qml/NotificationPopups.qml
Normal file
@ -0,0 +1,132 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Proton 4.0
|
||||
import Notifications 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property var backend
|
||||
|
||||
property ColorScheme colorScheme
|
||||
property var notifications
|
||||
property var mainWindow
|
||||
|
||||
property int notificationWhitelist: NotificationFilter.FilterConsts.All
|
||||
property int notificationBlacklist: NotificationFilter.FilterConsts.None
|
||||
|
||||
NotificationFilter {
|
||||
id: bannerNotificationFilter
|
||||
|
||||
source: root.notifications.all
|
||||
blacklist: Notifications.Group.Dialogs
|
||||
}
|
||||
|
||||
Banner {
|
||||
colorScheme: root.colorScheme
|
||||
notification: bannerNotificationFilter.topmost
|
||||
mainWindow: root.mainWindow
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.updateManualReady
|
||||
|
||||
Switch {
|
||||
id:autoUpdate
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Update automatically in the future")
|
||||
checked: root.backend.isAutomaticUpdateOn
|
||||
onClicked: root.backend.toggleAutomaticUpdate(autoUpdate.checked)
|
||||
}
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.updateForce
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.updateForceError
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.enableBeta
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.cacheUnavailable
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.cacheCantMove
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.diskFull
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.enableSplitMode
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.disableLocalCache
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.enableLocalCache
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.resetBridge
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.changeAllMailVisibility
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.deleteAccount
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.noKeychain
|
||||
}
|
||||
|
||||
NotificationDialog {
|
||||
colorScheme: root.colorScheme
|
||||
notification: root.notifications.rebuildKeychain
|
||||
}
|
||||
}
|
||||
54
internal/frontend/qt6/qml/Notifications/Notification.qml
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
default property var children
|
||||
|
||||
enum NotificationType {
|
||||
Info = 0,
|
||||
Success = 1,
|
||||
Warning = 2,
|
||||
Danger = 3
|
||||
}
|
||||
|
||||
// title is used in dialogs only
|
||||
property string title
|
||||
// description is used in banners and in dialogs as description
|
||||
property string description
|
||||
// brief is used in status view only
|
||||
property string brief
|
||||
|
||||
property string icon
|
||||
property list<Action> action
|
||||
property int type
|
||||
property int group
|
||||
|
||||
property bool dismissed: false
|
||||
property bool active: false
|
||||
readonly property var occurred: active ? new Date() : undefined
|
||||
|
||||
property var data
|
||||
|
||||
onActiveChanged: {
|
||||
dismissed = false
|
||||
}
|
||||
}
|
||||
114
internal/frontend/qt6/qml/Notifications/NotificationFilter.qml
Normal file
@ -0,0 +1,114 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQml.Models 2.12
|
||||
|
||||
// contains notifications that satisfy black- and whitelist and are sorted in time-occurred order
|
||||
ListModel {
|
||||
id: root
|
||||
|
||||
enum FilterConsts {
|
||||
None = 0,
|
||||
All = 255
|
||||
}
|
||||
|
||||
property int whitelist: NotificationFilter.FilterConsts.All
|
||||
property int blacklist: NotificationFilter.FilterConsts.None
|
||||
|
||||
property Notification topmost
|
||||
property var source
|
||||
|
||||
property bool componentCompleted: false
|
||||
Component.onCompleted: {
|
||||
root.componentCompleted = true
|
||||
root.rebuildList()
|
||||
}
|
||||
|
||||
// overriding get method to ignore any role and return directly object itself
|
||||
function get(row) {
|
||||
if (row < 0 || row >= count) {
|
||||
return undefined
|
||||
}
|
||||
return data(index(row, 0), Qt.DisplayRole)
|
||||
}
|
||||
|
||||
function rebuildList() {
|
||||
// avoid evaluation of the list before Component.onCompleted
|
||||
if (!root.componentCompleted) {
|
||||
return
|
||||
}
|
||||
|
||||
for (var i = 0; i < root.count; i++) {
|
||||
root.get(i).onActiveChanged.disconnect( root.updateList )
|
||||
}
|
||||
|
||||
root.clear()
|
||||
|
||||
if (!root.source) {
|
||||
return
|
||||
}
|
||||
|
||||
for (i = 0; i < root.source.length; i++) {
|
||||
var obj = root.source[i]
|
||||
if (obj.group & root.blacklist) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (!(obj.group & root.whitelist)) {
|
||||
continue
|
||||
}
|
||||
|
||||
root.append({obj})
|
||||
obj.onActiveChanged.connect( root.updateList )
|
||||
}
|
||||
}
|
||||
|
||||
function updateList() {
|
||||
var topmost = null
|
||||
|
||||
for (var i = 0; i < root.count; i++) {
|
||||
var obj = root.get(i)
|
||||
|
||||
if (!obj.active) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (topmost && (topmost.type > obj.type)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (topmost && (topmost.type === obj.type) && (topmost.occurred > obj.occurred)) {
|
||||
continue
|
||||
}
|
||||
|
||||
topmost = obj
|
||||
}
|
||||
|
||||
root.topmost = topmost
|
||||
}
|
||||
|
||||
onWhitelistChanged: {
|
||||
root.rebuildList()
|
||||
}
|
||||
onBlacklistChanged: {
|
||||
root.rebuildList()
|
||||
}
|
||||
onSourceChanged: {
|
||||
root.rebuildList()
|
||||
}
|
||||
}
|
||||
1021
internal/frontend/qt6/qml/Notifications/Notifications.qml
Normal file
6
internal/frontend/qt6/qml/Notifications/qmldir
Normal file
@ -0,0 +1,6 @@
|
||||
module Notifications
|
||||
depends QtQml 2.12
|
||||
|
||||
Notifications 1.0 Notifications.qml
|
||||
NotificationFilter 1.0 NotificationFilter.qml
|
||||
Notification 1.0 Notification.qml
|
||||
164
internal/frontend/qt6/qml/PortSettings.qml
Normal file
@ -0,0 +1,164 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Controls.impl 2.13
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
SettingsView {
|
||||
id: root
|
||||
|
||||
fillHeight: false
|
||||
|
||||
property bool _valuesChanged: (
|
||||
imapField.text*1 !== root.backend.portIMAP ||
|
||||
smtpField.text*1 !== root.backend.portSMTP
|
||||
)
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Default ports")
|
||||
type: Label.Heading
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Changes require reconfiguration of your email client. Bridge will automatically restart.")
|
||||
type: Label.Body
|
||||
color: root.colorScheme.text_weak
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 16
|
||||
|
||||
TextField {
|
||||
id: imapField
|
||||
colorScheme: root.colorScheme
|
||||
label: qsTr("IMAP port")
|
||||
Layout.preferredWidth: 160
|
||||
validator: root.validate
|
||||
}
|
||||
TextField {
|
||||
id: smtpField
|
||||
colorScheme: root.colorScheme
|
||||
label: qsTr("SMTP port")
|
||||
Layout.preferredWidth: 160
|
||||
validator: root.validate
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: root.colorScheme.border_weak
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
|
||||
Button {
|
||||
id: submitButton
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Save and restart")
|
||||
enabled: root._valuesChanged
|
||||
onClicked: {
|
||||
// removing error here because we may have set it manually (port occupied)
|
||||
imapField.error = false
|
||||
smtpField.error = false
|
||||
|
||||
// checking errors seperatly because we want to display "same port" error only once
|
||||
imapField.validate()
|
||||
if (imapField.error) {
|
||||
return
|
||||
}
|
||||
smtpField.validate()
|
||||
if (smtpField.error) {
|
||||
return
|
||||
}
|
||||
|
||||
submitButton.loading = true
|
||||
|
||||
// check both ports before returning an error
|
||||
var err = false
|
||||
err |= !isPortFree(imapField)
|
||||
err |= !isPortFree(smtpField)
|
||||
if (err) {
|
||||
submitButton.loading = false
|
||||
return
|
||||
}
|
||||
|
||||
root.backend.changePorts(imapField.text, smtpField.text)
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Cancel")
|
||||
onClicked: root.back()
|
||||
secondary: true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.backend
|
||||
|
||||
onChangePortFinished: submitButton.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
onBack: {
|
||||
root.setDefaultValues()
|
||||
}
|
||||
|
||||
function validate(port) {
|
||||
var num = port*1
|
||||
if (! (num > 1 && num < 65536) ) {
|
||||
return qsTr("Invalid port number")
|
||||
}
|
||||
|
||||
if (imapField.text == smtpField.text) {
|
||||
return qsTr("Port numbers must be different")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
function isPortFree(field) {
|
||||
var num = field.text*1
|
||||
if (num === root.backend.portIMAP) return true
|
||||
if (num === root.backend.portSMTP) return true
|
||||
if (!root.backend.isPortFree(num)) {
|
||||
field.error = true
|
||||
field.errorString = qsTr("Port occupied")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function setDefaultValues(){
|
||||
imapField.text = backend.portIMAP
|
||||
smtpField.text = backend.portSMTP
|
||||
}
|
||||
|
||||
Component.onCompleted: root.setDefaultValues()
|
||||
}
|
||||
23
internal/frontend/qt6/qml/Proton/Action.qml
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
|
||||
T.Action {
|
||||
property bool loading
|
||||
}
|
||||
134
internal/frontend/qt6/qml/Proton/ApplicationWindow.qml
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Window 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
|
||||
T.ApplicationWindow {
|
||||
id: root
|
||||
|
||||
property ColorScheme colorScheme
|
||||
|
||||
// popup priority based on types
|
||||
enum PopupType {
|
||||
Banner = 0,
|
||||
Dialog = 1
|
||||
}
|
||||
|
||||
// contains currently visible popup
|
||||
property var popupVisible: null
|
||||
|
||||
// list of all popups within ApplicationWindow
|
||||
property ListModel popups: ListModel {
|
||||
// overriding get method to ignore any role and return directly object itself
|
||||
function get(row) {
|
||||
if (row < 0 || row >= count) {
|
||||
return undefined
|
||||
}
|
||||
return data(index(row, 0), Qt.DisplayRole)
|
||||
}
|
||||
|
||||
onRowsInserted: {
|
||||
for (var i = first; i <= last; i++) {
|
||||
var obj = popups.get(i)
|
||||
obj.onShouldShowChanged.connect( root.processPopups )
|
||||
}
|
||||
|
||||
processPopups()
|
||||
}
|
||||
|
||||
onRowsAboutToBeRemoved: {
|
||||
for (var i = first; i <= last; i++ ) {
|
||||
var obj = popups.get(i)
|
||||
obj.onShouldShowChanged.disconnect( root.processPopups )
|
||||
|
||||
// if currently visible popup was removed
|
||||
if (root.popupVisible === obj) {
|
||||
root.popupVisible.visible = false
|
||||
root.popupVisible = null
|
||||
}
|
||||
}
|
||||
|
||||
processPopups()
|
||||
}
|
||||
}
|
||||
|
||||
function processPopups() {
|
||||
if ((root.popupVisible) && (!root.popupVisible.shouldShow)) {
|
||||
root.popupVisible.visible = false
|
||||
}
|
||||
|
||||
var topmost = null
|
||||
for (var i = 0; i < popups.count; i++) {
|
||||
var obj = popups.get(i)
|
||||
|
||||
if (obj.shouldShow === false) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (topmost && (topmost.popupType > obj.popupType)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (topmost && (topmost.popupType === obj.popupType) && (topmost.occurred > obj.occurred)) {
|
||||
continue
|
||||
}
|
||||
|
||||
topmost = obj
|
||||
}
|
||||
|
||||
if (root.popupVisible !== topmost) {
|
||||
if (root.popupVisible) {
|
||||
root.popupVisible.visible = false
|
||||
}
|
||||
root.popupVisible = topmost
|
||||
}
|
||||
|
||||
if (!root.popupVisible) {
|
||||
return
|
||||
}
|
||||
|
||||
root.popupVisible.visible = true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.popupVisible
|
||||
|
||||
onVisibleChanged: {
|
||||
if (root.popupVisible.visible) {
|
||||
return
|
||||
}
|
||||
|
||||
root.popupVisible = null
|
||||
root.processPopups()
|
||||
}
|
||||
}
|
||||
|
||||
color: root.colorScheme.background_norm
|
||||
|
||||
overlay.modal: Rectangle {
|
||||
color: root.colorScheme.backdrop_norm
|
||||
}
|
||||
|
||||
overlay.modeless: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
}
|
||||
245
internal/frontend/qt6/qml/Proton/Button.qml
Normal file
@ -0,0 +1,245 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import "." as Proton
|
||||
|
||||
T.Button {
|
||||
property ColorScheme colorScheme
|
||||
|
||||
property alias secondary: control.flat
|
||||
readonly property bool primary: !secondary
|
||||
readonly property bool isIcon: control.text === ""
|
||||
|
||||
property bool loading: false
|
||||
|
||||
property bool borderless: false
|
||||
|
||||
property int labelType: Proton.Label.LabelType.Body
|
||||
|
||||
property alias textVerticalAlignment: label.verticalAlignment
|
||||
property alias textHorizontalAlignment: label.horizontalAlignment
|
||||
|
||||
// TODO: store previous enabled state and restore it?
|
||||
// For now assuming that only enabled buttons could have loading state
|
||||
onLoadingChanged: {
|
||||
if (loading) {
|
||||
enabled = false
|
||||
} else {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(
|
||||
implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding
|
||||
)
|
||||
implicitHeight: Math.max(
|
||||
implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding
|
||||
)
|
||||
|
||||
padding: 8
|
||||
horizontalPadding: 16
|
||||
spacing: 10
|
||||
|
||||
font: label.font
|
||||
|
||||
icon.width: 16
|
||||
icon.height: 16
|
||||
icon.color: {
|
||||
if (primary && !isIcon) {
|
||||
return "#FFFFFF"
|
||||
} else {
|
||||
return control.colorScheme.text_norm
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: RowLayout {
|
||||
id: _contentItem
|
||||
spacing: control.spacing
|
||||
|
||||
Proton.Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: label
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
|
||||
visible: !control.isIcon
|
||||
text: control.text
|
||||
color: {
|
||||
if (primary && !isIcon) {
|
||||
return "#FFFFFF"
|
||||
} else {
|
||||
return control.colorScheme.text_norm
|
||||
}
|
||||
}
|
||||
opacity: control.enabled || control.loading ? 1.0 : 0.5
|
||||
|
||||
type: labelType
|
||||
}
|
||||
|
||||
ColorImage {
|
||||
id: iconImage
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
width: {
|
||||
// special case for loading since we want icon to be square for rotation animation
|
||||
if (control.loading) {
|
||||
return Math.min(control.icon.width, availableWidth, control.icon.height, availableHeight)
|
||||
}
|
||||
|
||||
return Math.min(control.icon.width, availableWidth)
|
||||
}
|
||||
height: {
|
||||
if (control.loading) {
|
||||
return width
|
||||
}
|
||||
|
||||
Math.min(control.icon.height, availableHeight)
|
||||
}
|
||||
|
||||
sourceSize.width: control.icon.width
|
||||
sourceSize.height: control.icon.height
|
||||
|
||||
color: control.icon.color
|
||||
source: control.loading ? "../icons/Loader_16.svg" : control.icon.source
|
||||
visible: control.loading || control.icon.source
|
||||
|
||||
RotationAnimation {
|
||||
target: iconImage
|
||||
loops: Animation.Infinite
|
||||
duration: 1000
|
||||
from: 0
|
||||
to: 360
|
||||
direction: RotationAnimation.Clockwise
|
||||
running: control.loading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 36
|
||||
implicitHeight: 36
|
||||
radius: Style.button_radius
|
||||
visible: true
|
||||
color: {
|
||||
if (!isIcon) {
|
||||
if (primary) {
|
||||
// Primary colors
|
||||
|
||||
if (control.down) {
|
||||
return control.colorScheme.interaction_norm_active
|
||||
}
|
||||
|
||||
if (control.enabled && (control.highlighted || control.hovered || control.checked || control.activeFocus)) {
|
||||
return control.colorScheme.interaction_norm_hover
|
||||
}
|
||||
|
||||
if (control.loading) {
|
||||
return control.colorScheme.interaction_norm_hover
|
||||
}
|
||||
|
||||
return control.colorScheme.interaction_norm
|
||||
} else {
|
||||
// Secondary colors
|
||||
|
||||
if (control.down) {
|
||||
return control.colorScheme.interaction_default_active
|
||||
}
|
||||
|
||||
if (control.enabled && (control.highlighted || control.hovered || control.checked || control.activeFocus)) {
|
||||
return control.colorScheme.interaction_default_hover
|
||||
}
|
||||
|
||||
if (control.loading) {
|
||||
return control.colorScheme.interaction_default_hover
|
||||
}
|
||||
|
||||
return control.colorScheme.interaction_default
|
||||
}
|
||||
} else {
|
||||
if (primary) {
|
||||
// Primary icon colors
|
||||
|
||||
if (control.down) {
|
||||
return control.colorScheme.interaction_default_active
|
||||
}
|
||||
|
||||
if (control.enabled && (control.highlighted || control.hovered || control.checked || control.activeFocus)) {
|
||||
return control.colorScheme.interaction_default_hover
|
||||
}
|
||||
|
||||
if (control.loading) {
|
||||
return control.colorScheme.interaction_default_hover
|
||||
}
|
||||
|
||||
return control.colorScheme.interaction_default
|
||||
} else {
|
||||
// Secondary icon colors
|
||||
|
||||
if (control.down) {
|
||||
return control.colorScheme.interaction_default_active
|
||||
}
|
||||
|
||||
if (control.enabled && (control.highlighted || control.hovered || control.checked || control.activeFocus)) {
|
||||
return control.colorScheme.interaction_default_hover
|
||||
}
|
||||
|
||||
if (control.loading) {
|
||||
return control.colorScheme.interaction_default_hover
|
||||
}
|
||||
|
||||
return control.colorScheme.interaction_default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
border.color: {
|
||||
return control.colorScheme.border_norm
|
||||
}
|
||||
border.width: secondary && !borderless ? 1 : 0
|
||||
|
||||
opacity: control.enabled || control.loading ? 1.0 : 0.5
|
||||
}
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!control.colorScheme) {
|
||||
console.trace()
|
||||
var next = root
|
||||
for (var i = 0; i<1000; i++) {
|
||||
console.log(i, next, "colorscheme", next.colorScheme)
|
||||
next = next.parent
|
||||
if (!next) break
|
||||
}
|
||||
console.error("ColorScheme not defined")
|
||||
}
|
||||
}
|
||||
}
|
||||
134
internal/frontend/qt6/qml/Proton/CheckBox.qml
Normal file
@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
|
||||
T.CheckBox {
|
||||
property ColorScheme colorScheme
|
||||
|
||||
property bool error: false
|
||||
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding,
|
||||
implicitIndicatorHeight + topPadding + bottomPadding)
|
||||
|
||||
padding: 0
|
||||
spacing: 8
|
||||
|
||||
indicator: Rectangle {
|
||||
implicitWidth: 20
|
||||
implicitHeight: 20
|
||||
radius: Style.checkbox_radius
|
||||
|
||||
x: text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
|
||||
y: control.topPadding + (control.availableHeight - height) / 2
|
||||
|
||||
color: {
|
||||
if (!checked) {
|
||||
return control.colorScheme.background_norm
|
||||
}
|
||||
|
||||
if (!control.enabled) {
|
||||
return control.colorScheme.field_disabled
|
||||
}
|
||||
|
||||
if (control.error) {
|
||||
return control.colorScheme.signal_danger
|
||||
}
|
||||
|
||||
if (control.hovered || control.activeFocus) {
|
||||
return control.colorScheme.interaction_norm_hover
|
||||
}
|
||||
|
||||
return control.colorScheme.interaction_norm
|
||||
}
|
||||
|
||||
border.width: control.checked ? 0 : 1
|
||||
border.color: {
|
||||
if (!control.enabled) {
|
||||
return control.colorScheme.field_disabled
|
||||
}
|
||||
|
||||
if (control.error) {
|
||||
return control.colorScheme.signal_danger
|
||||
}
|
||||
|
||||
if (control.hovered || control.activeFocus) {
|
||||
return control.colorScheme.interaction_norm_hover
|
||||
}
|
||||
|
||||
return control.colorScheme.field_norm
|
||||
}
|
||||
|
||||
ColorImage {
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
|
||||
width: parent.width - 4
|
||||
height: parent.height - 4
|
||||
sourceSize.width: parent.width - 4
|
||||
sourceSize.height: parent.height - 4
|
||||
color: "#FFFFFF"
|
||||
source: "../icons/ic-check.svg"
|
||||
visible: control.checkState === Qt.Checked
|
||||
}
|
||||
|
||||
// TODO: do we need PartiallyChecked state?
|
||||
|
||||
// Rectangle {
|
||||
// x: (parent.width - width) / 2
|
||||
// y: (parent.height - height) / 2
|
||||
// width: 16
|
||||
// height: 3
|
||||
// color: control.palette.text
|
||||
// visible: control.checkState === Qt.PartiallyChecked
|
||||
//}
|
||||
}
|
||||
|
||||
contentItem: CheckLabel {
|
||||
leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
|
||||
rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
|
||||
|
||||
text: control.text
|
||||
|
||||
color: {
|
||||
if (!enabled) {
|
||||
return control.colorScheme.text_disabled
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return control.colorScheme.signal_danger
|
||||
}
|
||||
|
||||
return control.colorScheme.text_norm
|
||||
}
|
||||
|
||||
font.family: Style.font_family
|
||||
font.weight: Style.fontWeight_400
|
||||
font.pixelSize: Style.body_font_size
|
||||
lineHeight: Style.body_line_height
|
||||
lineHeightMode: Text.FixedHeight
|
||||
font.letterSpacing: Style.body_letter_spacing
|
||||
}
|
||||
}
|
||||
92
internal/frontend/qt6/qml/Proton/ColorScheme.qml
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.13
|
||||
|
||||
QtObject {
|
||||
// should be a pointer to ColorScheme object
|
||||
property var prominent
|
||||
|
||||
// Primary
|
||||
property color primay_norm
|
||||
|
||||
// Interaction-norm
|
||||
property color interaction_norm
|
||||
property color interaction_norm_hover
|
||||
property color interaction_norm_active
|
||||
|
||||
// Text
|
||||
property color text_norm
|
||||
property color text_weak
|
||||
property color text_hint
|
||||
property color text_disabled
|
||||
property color text_invert
|
||||
|
||||
// Field
|
||||
property color field_norm
|
||||
property color field_hover
|
||||
property color field_disabled
|
||||
|
||||
// Border
|
||||
property color border_norm
|
||||
property color border_weak
|
||||
|
||||
// Background
|
||||
property color background_norm
|
||||
property color background_weak
|
||||
property color background_strong
|
||||
property color background_avatar
|
||||
|
||||
// Interaction-weak
|
||||
property color interaction_weak
|
||||
property color interaction_weak_hover
|
||||
property color interaction_weak_active
|
||||
|
||||
// Interaction-default
|
||||
property color interaction_default
|
||||
property color interaction_default_hover
|
||||
property color interaction_default_active
|
||||
|
||||
// Scrollbar
|
||||
property color scrollbar_norm
|
||||
property color scrollbar_hover
|
||||
|
||||
// Signal
|
||||
property color signal_danger
|
||||
property color signal_danger_hover
|
||||
property color signal_danger_active
|
||||
property color signal_warning
|
||||
property color signal_warning_hover
|
||||
property color signal_warning_active
|
||||
property color signal_success
|
||||
property color signal_success_hover
|
||||
property color signal_success_active
|
||||
property color signal_info
|
||||
property color signal_info_hover
|
||||
property color signal_info_active
|
||||
|
||||
// Shadows
|
||||
property color shadow_norm
|
||||
property color shadow_lifted
|
||||
|
||||
// Backdrop
|
||||
property color backdrop_norm
|
||||
|
||||
// Images
|
||||
property string welcome_img
|
||||
property string logo_img
|
||||
}
|
||||
195
internal/frontend/qt6/qml/Proton/ComboBox.qml
Normal file
@ -0,0 +1,195 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Window 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
|
||||
T.ComboBox {
|
||||
id: root
|
||||
|
||||
property ColorScheme colorScheme
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding,
|
||||
implicitIndicatorHeight + topPadding + bottomPadding)
|
||||
|
||||
leftPadding: 12 + (!root.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
|
||||
rightPadding: 12 + (root.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
|
||||
|
||||
topPadding: 5
|
||||
bottomPadding: 5
|
||||
|
||||
spacing: 8
|
||||
|
||||
font.family: Style.font_family
|
||||
font.weight: Style.fontWeight_400
|
||||
font.pixelSize: Style.body_font_size
|
||||
font.letterSpacing: Style.body_letter_spacing
|
||||
|
||||
contentItem: T.TextField {
|
||||
padding: 5
|
||||
|
||||
text: root.editable ? root.editText : root.displayText
|
||||
font: root.font
|
||||
|
||||
enabled: root.editable
|
||||
autoScroll: root.editable
|
||||
readOnly: root.down
|
||||
inputMethodHints: root.inputMethodHints
|
||||
validator: root.validator
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
|
||||
color: root.enabled ? root.colorScheme.text_norm : root.colorScheme.text_disabled
|
||||
selectionColor: root.colorScheme.interaction_norm
|
||||
selectedTextColor: root.colorScheme.text_invert
|
||||
placeholderTextColor: root.enabled ? root.colorScheme.text_hint : root.colorScheme.text_disabled
|
||||
|
||||
background: Rectangle {
|
||||
radius: Style.context_item_radius
|
||||
visible: root.enabled && root.editable && !root.flat
|
||||
border.color: {
|
||||
if (root.activeFocus) {
|
||||
return root.colorScheme.interaction_norm
|
||||
}
|
||||
|
||||
if (root.hovered || root.activeFocus) {
|
||||
return root.colorScheme.field_hover
|
||||
}
|
||||
|
||||
return root.colorScheme.field_norm
|
||||
}
|
||||
border.width: 1
|
||||
color: root.colorScheme.background_norm
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 140
|
||||
implicitHeight: 36
|
||||
radius: Style.context_item_radius
|
||||
color: {
|
||||
if (root.down) {
|
||||
return root.colorScheme.interaction_default_active
|
||||
}
|
||||
|
||||
if (root.enabled && root.hovered || root.activeFocus) {
|
||||
return root.colorScheme.interaction_default_hover
|
||||
}
|
||||
|
||||
if (!root.enabled) {
|
||||
return root.colorScheme.interaction_default
|
||||
}
|
||||
|
||||
return root.colorScheme.background_norm
|
||||
}
|
||||
|
||||
border.color: root.colorScheme.border_norm
|
||||
border.width: 1
|
||||
}
|
||||
|
||||
indicator: ColorImage {
|
||||
x: root.mirrored ? 12 : root.width - width - 12
|
||||
y: root.topPadding + (root.availableHeight - height) / 2
|
||||
color: root.enabled ? root.colorScheme.text_norm : root.colorScheme.text_disabled
|
||||
source: popup.visible ? "../icons/ic-chevron-up.svg" : "../icons/ic-chevron-down.svg"
|
||||
|
||||
sourceSize.width: 16
|
||||
sourceSize.height: 16
|
||||
}
|
||||
|
||||
|
||||
delegate: ItemDelegate {
|
||||
width: parent.width
|
||||
text: root.textRole ? (Array.isArray(root.model) ? modelData[root.textRole] : model[root.textRole]) : modelData
|
||||
|
||||
palette.text: {
|
||||
if (!root.enabled) {
|
||||
return root.colorScheme.text_disabled
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
return root.colorScheme.text_invert
|
||||
}
|
||||
|
||||
return root.colorScheme.text_norm
|
||||
}
|
||||
font: root.font
|
||||
|
||||
hoverEnabled: root.hoverEnabled
|
||||
|
||||
property bool selected: root.currentIndex === index
|
||||
|
||||
highlighted: root.highlightedIndex === index
|
||||
palette.highlightedText: selected ? root.colorScheme.text_invert : root.colorScheme.text_norm
|
||||
|
||||
background: PaddedRectangle {
|
||||
radius: Style.context_item_radius
|
||||
color: {
|
||||
if (parent.down) {
|
||||
return root.colorScheme.interaction_default_active
|
||||
}
|
||||
|
||||
if (parent.selected) {
|
||||
return root.colorScheme.interaction_norm
|
||||
}
|
||||
|
||||
if (parent.hovered || parent.highlighted) {
|
||||
return root.colorScheme.interaction_default_hover
|
||||
}
|
||||
|
||||
return root.colorScheme.interaction_default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
popup: T.Popup {
|
||||
y: root.height
|
||||
width: root.width
|
||||
height: Math.min(contentItem.implicitHeight, root.Window.height - topMargin - bottomMargin)
|
||||
topMargin: 8
|
||||
bottomMargin: 8
|
||||
|
||||
contentItem: Item {
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
|
||||
implicitHeight: contentHeight
|
||||
model: root.delegateModel
|
||||
currentIndex: root.highlightedIndex
|
||||
spacing: 4
|
||||
|
||||
T.ScrollIndicator.vertical: ScrollIndicator { }
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: root.colorScheme.background_norm
|
||||
radius: Style.dialog_radius
|
||||
border.color: root.colorScheme.border_weak
|
||||
border.width: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
80
internal/frontend/qt6/qml/Proton/Dialog.qml
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
|
||||
T.Dialog {
|
||||
id: root
|
||||
property ColorScheme colorScheme
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!ApplicationWindow.window) {
|
||||
return
|
||||
}
|
||||
|
||||
if (ApplicationWindow.window.popups === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
var obj = this
|
||||
ApplicationWindow.window.popups.append( { obj } )
|
||||
}
|
||||
|
||||
readonly property int popupType: ApplicationWindow.PopupType.Dialog
|
||||
|
||||
property bool shouldShow: false
|
||||
readonly property var occurred: shouldShow ? new Date() : undefined
|
||||
function open() {
|
||||
root.shouldShow = true
|
||||
}
|
||||
|
||||
function close() {
|
||||
root.shouldShow = false
|
||||
}
|
||||
|
||||
anchors.centerIn: Overlay.overlay
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
contentWidth + leftPadding + rightPadding,
|
||||
implicitHeaderWidth,
|
||||
implicitFooterWidth)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
contentHeight + topPadding + bottomPadding
|
||||
+ (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
|
||||
+ (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
|
||||
|
||||
padding: 24
|
||||
|
||||
background: Rectangle {
|
||||
color: root.colorScheme.background_norm
|
||||
radius: Style.dialog_radius
|
||||
}
|
||||
|
||||
// TODO: Add DropShadow here
|
||||
|
||||
T.Overlay.modal: Rectangle {
|
||||
color: root.colorScheme.backdrop_norm
|
||||
}
|
||||
|
||||
T.Overlay.modeless: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
}
|
||||
142
internal/frontend/qt6/qml/Proton/Label.qml
Normal file
@ -0,0 +1,142 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
|
||||
import "." as Proton
|
||||
|
||||
T.Label {
|
||||
id: root
|
||||
|
||||
property ColorScheme colorScheme
|
||||
|
||||
enum LabelType {
|
||||
// weight 700, size 28, height 36
|
||||
Heading,
|
||||
// weight 700, size 20, height 24
|
||||
Title,
|
||||
// weight 400, size 18, height 26
|
||||
Lead,
|
||||
// weight 400, size 14, height 20, spacing 0.2
|
||||
Body,
|
||||
// weight 600, size 14, height 20, spacing 0.2
|
||||
Body_semibold,
|
||||
// weight 700, size 14, height 20, spacing 0.2
|
||||
Body_bold,
|
||||
// weight 400, size 12, height 16, spacing 0.4
|
||||
Caption,
|
||||
// weight 600, size 12, height 16, spacing 0.4
|
||||
Caption_semibold,
|
||||
// weight 700, size 12, height 16, spacing 0.4
|
||||
Caption_bold
|
||||
}
|
||||
property int type: Proton.Label.LabelType.Body
|
||||
|
||||
color: root.enabled ? root.colorScheme.text_norm : root.colorScheme.text_disabled
|
||||
linkColor: root.colorScheme.interaction_norm
|
||||
palette.link: linkColor
|
||||
|
||||
font.family: Style.font_family
|
||||
lineHeightMode: Text.FixedHeight
|
||||
|
||||
font.weight: {
|
||||
switch (root.type) {
|
||||
case Proton.Label.LabelType.Heading:
|
||||
return Style.fontWeight_700
|
||||
case Proton.Label.LabelType.Title:
|
||||
return Style.fontWeight_700
|
||||
case Proton.Label.LabelType.Lead:
|
||||
return Style.fontWeight_400
|
||||
case Proton.Label.LabelType.Body:
|
||||
return Style.fontWeight_400
|
||||
case Proton.Label.LabelType.Body_semibold:
|
||||
return Style.fontWeight_600
|
||||
case Proton.Label.LabelType.Body_bold:
|
||||
return Style.fontWeight_700
|
||||
case Proton.Label.LabelType.Caption:
|
||||
return Style.fontWeight_400
|
||||
case Proton.Label.LabelType.Caption_semibold:
|
||||
return Style.fontWeight_600
|
||||
case Proton.Label.LabelType.Caption_bold:
|
||||
return Style.fontWeight_700
|
||||
}
|
||||
}
|
||||
|
||||
font.pixelSize: {
|
||||
switch (root.type) {
|
||||
case Proton.Label.LabelType.Heading:
|
||||
return Style.heading_font_size
|
||||
case Proton.Label.LabelType.Title:
|
||||
return Style.title_font_size
|
||||
case Proton.Label.LabelType.Lead:
|
||||
return Style.lead_font_size
|
||||
case Proton.Label.LabelType.Body:
|
||||
case Proton.Label.LabelType.Body_semibold:
|
||||
case Proton.Label.LabelType.Body_bold:
|
||||
return Style.body_font_size
|
||||
case Proton.Label.LabelType.Caption:
|
||||
case Proton.Label.LabelType.Caption_semibold:
|
||||
case Proton.Label.LabelType.Caption_bold:
|
||||
return Style.caption_font_size
|
||||
}
|
||||
}
|
||||
|
||||
lineHeight: {
|
||||
switch (root.type) {
|
||||
case Proton.Label.LabelType.Heading:
|
||||
return Style.heading_line_height
|
||||
case Proton.Label.LabelType.Title:
|
||||
return Style.title_line_height
|
||||
case Proton.Label.LabelType.Lead:
|
||||
return Style.lead_line_height
|
||||
case Proton.Label.LabelType.Body:
|
||||
case Proton.Label.LabelType.Body_semibold:
|
||||
case Proton.Label.LabelType.Body_bold:
|
||||
return Style.body_line_height
|
||||
case Proton.Label.LabelType.Caption:
|
||||
case Proton.Label.LabelType.Caption_semibold:
|
||||
case Proton.Label.LabelType.Caption_bold:
|
||||
return Style.caption_line_height
|
||||
}
|
||||
}
|
||||
|
||||
font.letterSpacing: {
|
||||
switch (root.type) {
|
||||
case Proton.Label.LabelType.Heading:
|
||||
case Proton.Label.LabelType.Title:
|
||||
case Proton.Label.LabelType.Lead:
|
||||
return 0
|
||||
case Proton.Label.LabelType.Body:
|
||||
case Proton.Label.LabelType.Body_semibold:
|
||||
case Proton.Label.LabelType.Body_bold:
|
||||
return Style.body_letter_spacing
|
||||
case Proton.Label.LabelType.Caption:
|
||||
case Proton.Label.LabelType.Caption_semibold:
|
||||
case Proton.Label.LabelType.Caption_bold:
|
||||
return Style.caption_letter_spacing
|
||||
}
|
||||
}
|
||||
|
||||
verticalAlignment: Text.AlignBottom
|
||||
|
||||
function link(url, text) {
|
||||
return `<a href="${url}">${text}</a>`
|
||||
}
|
||||
}
|
||||
72
internal/frontend/qt6/qml/Proton/Menu.qml
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
import QtQuick.Window 2.12
|
||||
import "."
|
||||
|
||||
T.Menu {
|
||||
id: control
|
||||
|
||||
property ColorScheme colorScheme
|
||||
|
||||
implicitWidth: Math.max(
|
||||
implicitBackgroundWidth + leftInset + rightInset,
|
||||
contentWidth + leftPadding + rightPadding
|
||||
)
|
||||
implicitHeight: Math.max(
|
||||
implicitBackgroundHeight + topInset + bottomInset,
|
||||
contentHeight + topPadding + bottomPadding
|
||||
)
|
||||
|
||||
margins: 0
|
||||
overlap: 1
|
||||
|
||||
delegate: MenuItem {
|
||||
colorScheme: control.colorScheme
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
|
||||
implicitHeight: contentHeight
|
||||
model: control.contentModel
|
||||
interactive: Window.window ? contentHeight > Window.window.height : false
|
||||
clip: true
|
||||
currentIndex: control.currentIndex
|
||||
|
||||
ScrollIndicator.vertical: ScrollIndicator {}
|
||||
}
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 200
|
||||
implicitHeight: 40
|
||||
color: colorScheme.background_norm
|
||||
border.width: 1
|
||||
border.color: colorScheme.border_weak
|
||||
radius: Style.account_row_radius
|
||||
}
|
||||
}
|
||||
72
internal/frontend/qt6/qml/Proton/MenuItem.qml
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
import "."
|
||||
|
||||
T.MenuItem {
|
||||
id: control
|
||||
|
||||
property ColorScheme colorScheme
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding,
|
||||
implicitIndicatorHeight + topPadding + bottomPadding)
|
||||
|
||||
padding: 6
|
||||
spacing: 6
|
||||
|
||||
icon.width: 24
|
||||
icon.height: 24
|
||||
icon.color: control.enabled ? control.colorScheme.text_norm : control.colorScheme.text_disabled
|
||||
|
||||
font.family: Style.font_family
|
||||
font.weight: Style.fontWeight_400
|
||||
font.pixelSize: Style.body_font_size
|
||||
font.letterSpacing: Style.body_letter_spacing
|
||||
|
||||
contentItem: IconLabel {
|
||||
id: iconLabel
|
||||
readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0
|
||||
readonly property real indicatorPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0
|
||||
leftPadding: !control.mirrored ? indicatorPadding : arrowPadding
|
||||
rightPadding: control.mirrored ? indicatorPadding : arrowPadding
|
||||
|
||||
spacing: control.spacing
|
||||
mirrored: control.mirrored
|
||||
display: control.display
|
||||
alignment: Qt.AlignLeft
|
||||
|
||||
icon: control.icon
|
||||
text: control.text
|
||||
font: control.font
|
||||
|
||||
color: control.enabled ? control.colorScheme.text_norm : control.colorScheme.text_disabled
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
implicitWidth: 164
|
||||
implicitHeight: 36
|
||||
radius: Style.button_radius
|
||||
color: control.down ? control.colorScheme.interaction_default_active : control.highlighted ? control.colorScheme.interaction_default_hover : control.colorScheme.interaction_default
|
||||
}
|
||||
}
|
||||
67
internal/frontend/qt6/qml/Proton/Popup.qml
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
|
||||
T.Popup {
|
||||
id: root
|
||||
property ColorScheme colorScheme
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!ApplicationWindow.window) {
|
||||
return
|
||||
}
|
||||
|
||||
if (ApplicationWindow.window.popups === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
var obj = this
|
||||
ApplicationWindow.window.popups.append( { obj } )
|
||||
}
|
||||
|
||||
property int popupType: ApplicationWindow.PopupType.Banner
|
||||
|
||||
property bool shouldShow: false
|
||||
readonly property var occurred: shouldShow ? new Date() : undefined
|
||||
function open() {
|
||||
root.shouldShow = true
|
||||
}
|
||||
|
||||
function close() {
|
||||
root.shouldShow = false
|
||||
}
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
contentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
contentHeight + topPadding + bottomPadding)
|
||||
|
||||
// TODO: Add DropShadow here
|
||||
|
||||
T.Overlay.modal: Rectangle {
|
||||
color: root.colorScheme.backdrop_norm
|
||||
}
|
||||
|
||||
T.Overlay.modeless: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
}
|
||||
115
internal/frontend/qt6/qml/Proton/RadioButton.qml
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
|
||||
T.RadioButton {
|
||||
property ColorScheme colorScheme
|
||||
|
||||
property bool error: false
|
||||
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding,
|
||||
implicitIndicatorHeight + topPadding + bottomPadding)
|
||||
|
||||
padding: 0
|
||||
spacing: 8
|
||||
|
||||
indicator: Rectangle {
|
||||
implicitWidth: 20
|
||||
implicitHeight: 20
|
||||
radius: width / 2
|
||||
|
||||
x: text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
|
||||
y: control.topPadding + (control.availableHeight - height) / 2
|
||||
|
||||
color: control.colorScheme.background_norm
|
||||
border.width: 1
|
||||
border.color: {
|
||||
if (!control.enabled) {
|
||||
return control.colorScheme.field_disabled
|
||||
}
|
||||
|
||||
if (control.error) {
|
||||
return control.colorScheme.signal_danger
|
||||
}
|
||||
|
||||
if (control.hovered || control.activeFocus) {
|
||||
return control.colorScheme.interaction_norm_hover
|
||||
}
|
||||
|
||||
return control.colorScheme.field_norm
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
width: 8
|
||||
height: 8
|
||||
radius: width / 2
|
||||
color: {
|
||||
if (!control.enabled) {
|
||||
return control.colorScheme.field_disabled
|
||||
}
|
||||
|
||||
if (control.error) {
|
||||
return control.colorScheme.signal_danger
|
||||
}
|
||||
|
||||
if (control.hovered || control.activeFocus) {
|
||||
return control.colorScheme.interaction_norm_hover
|
||||
}
|
||||
|
||||
return control.colorScheme.interaction_norm
|
||||
}
|
||||
visible: control.checked
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: CheckLabel {
|
||||
leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
|
||||
rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
|
||||
|
||||
text: control.text
|
||||
|
||||
color: {
|
||||
if (!enabled) {
|
||||
return control.colorScheme.text_disabled
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return control.colorScheme.signal_danger
|
||||
}
|
||||
|
||||
return control.colorScheme.text_norm
|
||||
}
|
||||
|
||||
font.family: Style.font_family
|
||||
font.weight: Style.fontWeight_400
|
||||
font.pixelSize: Style.body_font_size
|
||||
lineHeight: Style.body_line_height
|
||||
lineHeightMode: Text.FixedHeight
|
||||
font.letterSpacing: Style.body_letter_spacing
|
||||
}
|
||||
}
|
||||
394
internal/frontend/qt6/qml/Proton/Style.qml
Normal file
@ -0,0 +1,394 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
pragma Singleton
|
||||
import QtQml 2.13
|
||||
import QtQuick 2.12
|
||||
|
||||
import "./"
|
||||
|
||||
// https://wiki.qt.io/Qml_Styling
|
||||
// http://imaginativethinking.ca/make-qml-component-singleton/
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
// TODO: Once we will use Qt >=5.15 this should be refactored with inline components as follows:
|
||||
// https://doc.qt.io/qt-5/qtqml-documents-definetypes.html#inline-components
|
||||
|
||||
// component ColorScheme: QtObject {
|
||||
// property color primay_norm
|
||||
// ...
|
||||
// }
|
||||
|
||||
property ColorScheme lightStyle: ColorScheme {
|
||||
id: _lightStyle
|
||||
|
||||
prominent: lightProminentStyle
|
||||
|
||||
// Primary
|
||||
primay_norm: "#6D4AFF"
|
||||
|
||||
// Interaction-norm
|
||||
interaction_norm: "#6D4AFF"
|
||||
interaction_norm_hover: "#4D34B3"
|
||||
interaction_norm_active: "#372580"
|
||||
|
||||
// Text
|
||||
text_norm: "#0C0C14"
|
||||
text_weak: "#706D6B"
|
||||
text_hint: "#8F8D8A"
|
||||
text_disabled: "#C2BFBC"
|
||||
text_invert: "#FFFFFF"
|
||||
|
||||
// Field
|
||||
field_norm: "#ADABA8"
|
||||
field_hover: "#8F8D8A"
|
||||
field_disabled: "#D1CFCD"
|
||||
|
||||
// Border
|
||||
border_norm: "#D1CFCD"
|
||||
border_weak: "#EAE7E4"
|
||||
|
||||
// Background
|
||||
background_norm: "#FFFFFF"
|
||||
background_weak: "#F5F4F2"
|
||||
background_strong: "#EAE7E4"
|
||||
background_avatar: "#C2BFBC"
|
||||
|
||||
// Interaction-weak
|
||||
interaction_weak: "#D1CFCD"
|
||||
interaction_weak_hover: "#C2BFBC"
|
||||
interaction_weak_active: "#A8A6A3"
|
||||
|
||||
// Interaction-default
|
||||
interaction_default: Qt.rgba(0,0,0,0)
|
||||
interaction_default_hover: Qt.rgba(194./255., 191./255., 188./255., 0.2)
|
||||
interaction_default_active: Qt.rgba(194./255., 191./255., 188./255., 0.4)
|
||||
|
||||
// Scrollbar
|
||||
scrollbar_norm: "#D1CFCD"
|
||||
scrollbar_hover: "#C2BFBC"
|
||||
|
||||
// Signal
|
||||
signal_danger: "#DC3251"
|
||||
signal_danger_hover: "#F74F6D"
|
||||
signal_danger_active: "#B72346"
|
||||
signal_warning: "#FF9900"
|
||||
signal_warning_hover: "#FFB800"
|
||||
signal_warning_active: "#FF851A"
|
||||
signal_success: "#1EA885"
|
||||
signal_success_hover: "#23C299"
|
||||
signal_success_active: "#198F71"
|
||||
signal_info: "#239ECE"
|
||||
signal_info_hover: "#27B1E8"
|
||||
signal_info_active: "#1F83B5"
|
||||
|
||||
// Shadows
|
||||
shadow_norm: Qt.rgba(0,0,0, 0.1) // #000000 10% x:0 y:1 blur:4
|
||||
shadow_lifted: Qt.rgba(0,0,0, 0.16) // #000000 16% x:0 y:8 blur:24
|
||||
|
||||
// Backdrop
|
||||
backdrop_norm: Qt.rgba(12./255., 12./255., 20./255., 0.32)
|
||||
|
||||
// Images
|
||||
welcome_img: "icons/img-welcome.png"
|
||||
logo_img: "icons/product_logos.svg"
|
||||
}
|
||||
|
||||
property ColorScheme lightProminentStyle: ColorScheme {
|
||||
id: _lightProminentStyle
|
||||
|
||||
prominent: this
|
||||
|
||||
// Primary
|
||||
primay_norm: "#8A6EFF"
|
||||
|
||||
// Interaction-norm
|
||||
interaction_norm: "#6D4AFF"
|
||||
interaction_norm_hover: "#7C5CFF"
|
||||
interaction_norm_active: "#8A6EFF"
|
||||
|
||||
// Text
|
||||
text_norm: "#FFFFFF"
|
||||
text_weak: "#9282D4"
|
||||
text_hint: "#544399"
|
||||
text_disabled: "#4A398F"
|
||||
text_invert: "#1B1340"
|
||||
|
||||
// Field
|
||||
field_norm: "#9282D4"
|
||||
field_hover: "#7C5CFF"
|
||||
field_disabled: "#38277A"
|
||||
|
||||
// Border
|
||||
border_norm: "#413085"
|
||||
border_weak: "#3C2B80"
|
||||
|
||||
// Background
|
||||
background_norm: "#1B1340"
|
||||
background_weak: "#271C57"
|
||||
background_strong: "#38277A"
|
||||
background_avatar: "#6D4AFF"
|
||||
|
||||
// Interaction-weak
|
||||
interaction_weak: "#4A398F"
|
||||
interaction_weak_hover: "#6D4AFF"
|
||||
interaction_weak_active: "#8A6EFF"
|
||||
|
||||
// Interaction-default
|
||||
interaction_default: Qt.rgba(0,0,0,0)
|
||||
interaction_default_hover: Qt.rgba(68./255., 78./255., 114./255., 0.2)
|
||||
interaction_default_active: Qt.rgba(68./255., 78./255., 114./255., 0.3)
|
||||
|
||||
// Scrollbar
|
||||
scrollbar_norm: "#413085"
|
||||
scrollbar_hover: "#4A398F"
|
||||
|
||||
// Signal
|
||||
signal_danger: "#F5385A"
|
||||
signal_danger_hover: "#FF5473"
|
||||
signal_danger_active: "#DC3251"
|
||||
signal_warning: "#FF9900"
|
||||
signal_warning_hover: "#FFB800"
|
||||
signal_warning_active: "#FF8419"
|
||||
signal_success: "#1EA885"
|
||||
signal_success_hover: "#23C299"
|
||||
signal_success_active: "#198F71"
|
||||
signal_info: "#2C89DB"
|
||||
signal_info_hover: "#3491E3"
|
||||
signal_info_active: "#1F83B5"
|
||||
|
||||
// Shadows
|
||||
shadow_norm: Qt.rgba(0,0,0, 0.32) // #000000 32% x:0 y:1 blur:4
|
||||
shadow_lifted: Qt.rgba(0,0,0, 0.40) // #000000 40% x:0 y:8 blur:24
|
||||
|
||||
// Backdrop
|
||||
backdrop_norm: Qt.rgba(0,0,0, 0.32)
|
||||
|
||||
// Images
|
||||
welcome_img: "icons/img-welcome-dark.png"
|
||||
logo_img: "icons/product_logos_dark.svg"
|
||||
}
|
||||
|
||||
property ColorScheme darkStyle: ColorScheme {
|
||||
id: _darkStyle
|
||||
|
||||
prominent: darkProminentStyle
|
||||
|
||||
// Primary
|
||||
primay_norm: "#8A6EFF"
|
||||
|
||||
// Interaction-norm
|
||||
interaction_norm: "#6D4AFF"
|
||||
interaction_norm_hover: "#7C5CFF"
|
||||
interaction_norm_active: "#8A6EFF"
|
||||
|
||||
// Text
|
||||
text_norm: "#FFFFFF"
|
||||
text_weak: "#A7A4B5"
|
||||
text_hint: "#6D697D"
|
||||
text_disabled: "#5B576B"
|
||||
text_invert: "#1C1B24"
|
||||
|
||||
// Field
|
||||
field_norm: "#5B576B"
|
||||
field_hover: "#6D697D"
|
||||
field_disabled: "#3F3B4C"
|
||||
|
||||
// Border
|
||||
border_norm: "#4A4658"
|
||||
border_weak: "#343140"
|
||||
|
||||
// Background
|
||||
background_norm: "#1C1B24"
|
||||
background_weak: "#292733"
|
||||
background_strong: "#3F3B4C"
|
||||
background_avatar: "#6D4AFF"
|
||||
|
||||
// Interaction-weak
|
||||
interaction_weak: "#4A4658"
|
||||
interaction_weak_hover: "#5B576B"
|
||||
interaction_weak_active: "#6D697D"
|
||||
|
||||
// Interaction-default
|
||||
interaction_default: "#00000000"
|
||||
interaction_default_hover: Qt.rgba(91./255.,87./255.,107./255.,0.2)
|
||||
interaction_default_active: Qt.rgba(91./255.,87./255.,107./255.,0.4)
|
||||
|
||||
// Scrollbar
|
||||
scrollbar_norm: "#4A4658"
|
||||
scrollbar_hover: "#5B576B"
|
||||
|
||||
// Signal
|
||||
signal_danger: "#F5385A"
|
||||
signal_danger_hover: "#FF5473"
|
||||
signal_danger_active: "#DC3251"
|
||||
signal_warning: "#FF9900"
|
||||
signal_warning_hover: "#FFB800"
|
||||
signal_warning_active: "#FF8419"
|
||||
signal_success: "#1EA885"
|
||||
signal_success_hover: "#23C299"
|
||||
signal_success_active: "#198F71"
|
||||
signal_info: "#239ECE"
|
||||
signal_info_hover: "#27B1E8"
|
||||
signal_info_active: "#1F83B5"
|
||||
|
||||
// Shadows
|
||||
shadow_norm: Qt.rgba(0,0,0,0.4) // #000000 40% x+0 y+1 blur:4
|
||||
shadow_lifted: Qt.rgba(0,0,0,0.48) // #000000 48% x+0 y+8 blur:24
|
||||
|
||||
// Backdrop
|
||||
backdrop_norm: Qt.rgba(0,0,0,0.32)
|
||||
|
||||
// Images
|
||||
welcome_img: "icons/img-welcome-dark.png"
|
||||
logo_img: "icons/product_logos_dark.svg"
|
||||
}
|
||||
|
||||
property ColorScheme darkProminentStyle: ColorScheme {
|
||||
id: _darkProminentStyle
|
||||
|
||||
prominent: this
|
||||
|
||||
// Primary
|
||||
primay_norm: "#8A6EFF"
|
||||
|
||||
// Interaction-norm
|
||||
interaction_norm: "#6D4AFF"
|
||||
interaction_norm_hover: "#7C5CFF"
|
||||
interaction_norm_active: "#8A6EFF"
|
||||
|
||||
// Text
|
||||
text_norm: "#FFFFFF"
|
||||
text_weak: "#A7A4B5"
|
||||
text_hint: "#6D697D"
|
||||
text_disabled: "#5B576B"
|
||||
text_invert: "#1C1B24"
|
||||
|
||||
// Field
|
||||
field_norm: "#5B576B"
|
||||
field_hover: "#6D697D"
|
||||
field_disabled: "#3F3B4C"
|
||||
|
||||
// Border
|
||||
border_norm: "#4A4658"
|
||||
border_weak: "#343140"
|
||||
|
||||
// Background
|
||||
background_norm: "#16141c"
|
||||
background_weak: "#292733"
|
||||
background_strong: "#3F3B4C"
|
||||
background_avatar: "#6D4AFF"
|
||||
|
||||
// Interaction-weak
|
||||
interaction_weak: "#4A4658"
|
||||
interaction_weak_hover: "#5B576B"
|
||||
interaction_weak_active: "#6D697D"
|
||||
|
||||
// Interaction-default
|
||||
interaction_default: "#00000000"
|
||||
interaction_default_hover: Qt.rgba(91./255.,87./255.,107./255.,0.2)
|
||||
interaction_default_active: Qt.rgba(91./255.,87./255.,107./255.,0.4)
|
||||
|
||||
// Scrollbar
|
||||
scrollbar_norm: "#4A4658"
|
||||
scrollbar_hover: "#5B576B"
|
||||
|
||||
// Signal
|
||||
signal_danger: "#F5385A"
|
||||
signal_danger_hover: "#FF5473"
|
||||
signal_danger_active: "#DC3251"
|
||||
signal_warning: "#FF9900"
|
||||
signal_warning_hover: "#FFB800"
|
||||
signal_warning_active: "#FF8419"
|
||||
signal_success: "#1EA885"
|
||||
signal_success_hover: "#23C299"
|
||||
signal_success_active: "#198F71"
|
||||
signal_info: "#239ECE"
|
||||
signal_info_hover: "#27B1E8"
|
||||
signal_info_active: "#1F83B5"
|
||||
|
||||
// Shadows
|
||||
shadow_norm: Qt.rgba(0,0,0,0.4) // #000000 40% x+0 y+1 blur:4
|
||||
shadow_lifted: Qt.rgba(0,0,0,0.48) // #000000 48% x+0 y+8 blur:24
|
||||
|
||||
// Backdrop
|
||||
backdrop_norm: Qt.rgba(0,0,0,0.32)
|
||||
|
||||
// Images
|
||||
welcome_img: "icons/img-welcome-dark.png"
|
||||
logo_img: "icons/product_logos_dark.svg"
|
||||
}
|
||||
|
||||
property ColorScheme currentStyle: lightStyle
|
||||
|
||||
property string font_family: {
|
||||
switch (Qt.platform.os) {
|
||||
case "windows":
|
||||
return "Segoe UI"
|
||||
case "osx":
|
||||
return "SF Pro Display"
|
||||
case "linux":
|
||||
return "Ubuntu"
|
||||
default:
|
||||
console.error("Unknown platform")
|
||||
}
|
||||
}
|
||||
|
||||
property real px : 1.00 // px
|
||||
|
||||
property real input_radius : 8 * root.px // px
|
||||
property real button_radius : 8 * root.px // px
|
||||
property real checkbox_radius : 4 * root.px // px
|
||||
property real avatar_radius : 8 * root.px // px
|
||||
property real big_avatar_radius : 12 * root.px // px
|
||||
property real account_hover_radius : 12 * root.px // px
|
||||
property real account_row_radius : 12 * root.px // px
|
||||
property real context_item_radius : 8 * root.px // px
|
||||
property real banner_radius : 12 * root.px // px
|
||||
property real dialog_radius : 12 * root.px // px
|
||||
property real card_radius : 12 * root.px // px
|
||||
property real storage_bar_radius : 3 * root.px // px
|
||||
property real tooltip_radius : 8 * root.px // px
|
||||
|
||||
property int heading_font_size: 28
|
||||
property int heading_line_height: 36
|
||||
|
||||
property int title_font_size: 20
|
||||
property int title_line_height: 24
|
||||
|
||||
property int lead_font_size: 18
|
||||
property int lead_line_height: 26
|
||||
|
||||
property int body_font_size: 14
|
||||
property int body_line_height: 20
|
||||
property real body_letter_spacing: 0.2 * root.px
|
||||
|
||||
property int caption_font_size: 12
|
||||
property int caption_line_height: 16
|
||||
property real caption_letter_spacing: 0.4 * root.px
|
||||
|
||||
property int fontWeight_100: Font.Thin
|
||||
property int fontWeight_200: Font.Light
|
||||
property int fontWeight_300: Font.ExtraLight
|
||||
property int fontWeight_400: Font.Normal
|
||||
property int fontWeight_500: Font.Medium
|
||||
property int fontWeight_600: Font.DemiBold
|
||||
property int fontWeight_700: Font.Bold
|
||||
property int fontWeight_800: Font.ExtraBold
|
||||
property int fontWeight_900: Font.Black
|
||||
}
|
||||
150
internal/frontend/qt6/qml/Proton/Switch.qml
Normal file
@ -0,0 +1,150 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
|
||||
T.Switch {
|
||||
property ColorScheme colorScheme
|
||||
|
||||
property bool loading: false
|
||||
|
||||
// TODO: store previous enabled state and restore it?
|
||||
// For now assuming that only enabled buttons could have loading state
|
||||
onLoadingChanged: {
|
||||
if (loading) {
|
||||
enabled = false
|
||||
} else {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
|
||||
implicitContentWidth + leftPadding + rightPadding)
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
implicitContentHeight + topPadding + bottomPadding,
|
||||
implicitIndicatorHeight + topPadding + bottomPadding)
|
||||
|
||||
padding: 0
|
||||
spacing: 7
|
||||
|
||||
indicator: Rectangle {
|
||||
implicitWidth: 40
|
||||
implicitHeight: 24
|
||||
|
||||
x: text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
|
||||
y: control.topPadding + (control.availableHeight - height) / 2
|
||||
|
||||
radius: height / 2.
|
||||
color: control.enabled || control.loading ? control.colorScheme.background_norm : control.colorScheme.background_strong
|
||||
border.width: control.enabled && !loading ? 1 : 0
|
||||
border.color: control.hovered ? control.colorScheme.field_hover : control.colorScheme.field_norm
|
||||
|
||||
Rectangle {
|
||||
x: Math.max(0, Math.min(parent.width - width, control.visualPosition * parent.width - (width / 2)))
|
||||
y: (parent.height - height) / 2
|
||||
width: 24
|
||||
height: 24
|
||||
radius: parent.radius
|
||||
|
||||
visible: !loading
|
||||
|
||||
color: {
|
||||
if (!control.enabled) {
|
||||
return control.colorScheme.field_disabled
|
||||
}
|
||||
|
||||
if (control.checked) {
|
||||
if (control.hovered || control.activeFocus) {
|
||||
return control.colorScheme.interaction_norm_hover
|
||||
}
|
||||
|
||||
return control.colorScheme.interaction_norm
|
||||
}
|
||||
|
||||
if (control.hovered || control.activeFocus) {
|
||||
return control.colorScheme.field_hover
|
||||
}
|
||||
|
||||
return control.colorScheme.field_norm
|
||||
}
|
||||
|
||||
ColorImage {
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
|
||||
width: 16
|
||||
height: 16
|
||||
sourceSize.width: 16
|
||||
sourceSize.height: 16
|
||||
color: "#FFFFFF"
|
||||
source: "../icons/ic-check.svg"
|
||||
visible: control.checked
|
||||
}
|
||||
|
||||
Behavior on x {
|
||||
enabled: !control.down
|
||||
SmoothedAnimation { velocity: 200 }
|
||||
}
|
||||
}
|
||||
|
||||
ColorImage {
|
||||
id: loadingImage
|
||||
x: parent.width - width
|
||||
y: (parent.height - height) / 2
|
||||
|
||||
width: 18
|
||||
height: 18
|
||||
sourceSize.width: 18
|
||||
sourceSize.height: 18
|
||||
color: control.colorScheme.interaction_norm_hover
|
||||
source: "../icons/Loader_16.svg"
|
||||
visible: control.loading
|
||||
|
||||
RotationAnimation {
|
||||
target: loadingImage
|
||||
loops: Animation.Infinite
|
||||
duration: 1000
|
||||
from: 0
|
||||
to: 360
|
||||
direction: RotationAnimation.Clockwise
|
||||
running: control.loading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: CheckLabel {
|
||||
id: label
|
||||
leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
|
||||
rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
|
||||
|
||||
text: control.text
|
||||
|
||||
color: control.enabled || control.loading ? control.colorScheme.text_norm : control.colorScheme.text_disabled
|
||||
|
||||
font.family: Style.font_family
|
||||
font.weight: Style.fontWeight_400
|
||||
font.pixelSize: Style.body_font_size
|
||||
lineHeight: Style.body_line_height
|
||||
lineHeightMode: Text.FixedHeight
|
||||
font.letterSpacing: Style.body_letter_spacing
|
||||
}
|
||||
}
|
||||
370
internal/frontend/qt6/qml/Proton/TextArea.qml
Normal file
@ -0,0 +1,370 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import "." as Proton
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
property ColorScheme colorScheme
|
||||
|
||||
property alias background: control.background
|
||||
property alias bottomInset: control.bottomInset
|
||||
//property alias flickable: control.flickable
|
||||
property alias focusReason: control.focusReason
|
||||
property alias hoverEnabled: control.hoverEnabled
|
||||
property alias hovered: control.hovered
|
||||
property alias implicitBackgroundHeight: control.implicitBackgroundHeight
|
||||
property alias implicitBackgroundWidth: control.implicitBackgroundWidth
|
||||
property alias leftInset: control.leftInset
|
||||
property alias palette: control.palette
|
||||
property alias placeholderText: control.placeholderText
|
||||
property alias placeholderTextColor: control.placeholderTextColor
|
||||
property alias rightInset: control.rightInset
|
||||
property alias topInset: control.topInset
|
||||
property alias activeFocusOnPress: control.activeFocusOnPress
|
||||
property alias baseUrl: control.baseUrl
|
||||
property alias bottomPadding: control.bottomPadding
|
||||
property alias canPaste: control.canPaste
|
||||
property alias canRedo: control.canRedo
|
||||
property alias canUndo: control.canUndo
|
||||
property alias color: control.color
|
||||
property alias contentHeight: control.contentHeight
|
||||
property alias contentWidth: control.contentWidth
|
||||
property alias cursorDelegate: control.cursorDelegate
|
||||
property alias cursorPosition: control.cursorPosition
|
||||
property alias cursorRectangle: control.cursorRectangle
|
||||
property alias cursorVisible: control.cursorVisible
|
||||
property alias effectiveHorizontalAlignment: control.effectiveHorizontalAlignment
|
||||
property alias font: control.font
|
||||
property alias horizontalAlignment: control.horizontalAlignment
|
||||
property alias hoveredLink: control.hoveredLink
|
||||
property alias inputMethodComposing: control.inputMethodComposing
|
||||
property alias inputMethodHints: control.inputMethodHints
|
||||
property alias leftPadding: control.leftPadding
|
||||
property alias length: control.length
|
||||
property alias lineCount: control.lineCount
|
||||
property alias mouseSelectionMode: control.mouseSelectionMode
|
||||
property alias overwriteMode: control.overwriteMode
|
||||
property alias padding: control.padding
|
||||
property alias persistentSelection: control.persistentSelection
|
||||
property alias preeditText: control.preeditText
|
||||
property alias readOnly: control.readOnly
|
||||
property alias renderType: control.renderType
|
||||
property alias rightPadding: control.rightPadding
|
||||
property alias selectByKeyboard: control.selectByKeyboard
|
||||
property alias selectByMouse: control.selectByMouse
|
||||
property alias selectedText: control.selectedText
|
||||
property alias selectedTextColor: control.selectedTextColor
|
||||
property alias selectionColor: control.selectionColor
|
||||
property alias selectionEnd: control.selectionEnd
|
||||
property alias selectionStart: control.selectionStart
|
||||
property alias tabStopDistance: control.tabStopDistance
|
||||
property alias text: control.text
|
||||
property alias textDocument: control.textDocument
|
||||
property alias textFormat: control.textFormat
|
||||
property alias textMargin: control.textMargin
|
||||
property alias topPadding: control.topPadding
|
||||
// We are using our own type of validators. It should be a function
|
||||
// returning an error string in case of error and undefined if no error
|
||||
property var validator
|
||||
property alias verticalAlignment: control.verticalAlignment
|
||||
property alias wrapMode: control.wrapMode
|
||||
|
||||
implicitWidth: children[0].implicitWidth
|
||||
implicitHeight: children[0].implicitHeight
|
||||
|
||||
property alias label: label.text
|
||||
property alias hint: hint.text
|
||||
property string assistiveText
|
||||
property string errorString
|
||||
|
||||
property bool error: false
|
||||
|
||||
signal editingFinished()
|
||||
|
||||
function append(text) { return control.append(text) }
|
||||
function clear() { return control.clear() }
|
||||
function copy() { return control.copy() }
|
||||
function cut() { return control.cut() }
|
||||
function deselect() { return control.deselect() }
|
||||
function getFormattedText(start, end) { return control.getFormattedText(start, end) }
|
||||
function getText(start, end) { return control.getText(start, end) }
|
||||
function insert(position, text) { return control.insert(position, text) }
|
||||
function isRightToLeft(start, end) { return control.isRightToLeft(start, end) }
|
||||
function linkAt(x, y) { return control.linkAt(x, y) }
|
||||
function moveCursorSelection(position, mode) { return control.moveCursorSelection(position, mode) }
|
||||
function paste() { return control.paste() }
|
||||
function positionAt(x, y) { return control.positionAt(x, y) }
|
||||
function positionToRectangle(position) { return control.positionToRectangle(position) }
|
||||
function redo() { return control.redo() }
|
||||
function remove(start, end) { return control.remove(start, end) }
|
||||
function select(start, end) { return control.select(start, end) }
|
||||
function selectAll() { return control.selectAll() }
|
||||
function selectWord() { return control.selectWord() }
|
||||
function undo() { return control.undo() }
|
||||
|
||||
// Calculates the height of the component to make exactly lineNum visible in edit area
|
||||
function heightForLinesVisible(lineNum) {
|
||||
var totalHeight = 0
|
||||
totalHeight += headerLayout.height
|
||||
totalHeight += footerLayout.height
|
||||
totalHeight += control.topPadding + control.bottomPadding
|
||||
totalHeight += lineNum * fontMetrics.height
|
||||
return totalHeight
|
||||
}
|
||||
|
||||
FontMetrics {
|
||||
id: fontMetrics
|
||||
font: control.font
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
id: headerLayout
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
Proton.Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: label
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
color: root.enabled ? root.colorScheme.text_norm : root.colorScheme.text_disabled
|
||||
|
||||
type: Proton.Label.LabelType.Body_semibold
|
||||
}
|
||||
|
||||
Proton.Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: hint
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
color: root.enabled ? root.colorScheme.text_weak : root.colorScheme.text_disabled
|
||||
horizontalAlignment: Text.AlignRight
|
||||
type: Proton.Label.LabelType.Caption
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: controlView
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
clip: true
|
||||
|
||||
T.TextArea {
|
||||
id: control
|
||||
|
||||
implicitWidth: Math.max(
|
||||
contentWidth + leftPadding + rightPadding,
|
||||
implicitBackgroundWidth + leftInset + rightInset,
|
||||
placeholder.implicitWidth + leftPadding + rightPadding
|
||||
)
|
||||
implicitHeight: Math.max(
|
||||
contentHeight + topPadding + bottomPadding,
|
||||
implicitBackgroundHeight + topInset + bottomInset,
|
||||
placeholder.implicitHeight + topPadding + bottomPadding
|
||||
)
|
||||
|
||||
topPadding: 8
|
||||
bottomPadding: 8
|
||||
leftPadding: 12
|
||||
rightPadding: 12
|
||||
|
||||
font.family: Style.font_family
|
||||
font.weight: Style.fontWeight_400
|
||||
font.pixelSize: Style.body_font_size
|
||||
font.letterSpacing: Style.body_letter_spacing
|
||||
|
||||
color: control.enabled ? root.colorScheme.text_norm : root.colorScheme.text_disabled
|
||||
placeholderTextColor: control.enabled ? root.colorScheme.text_hint : root.colorScheme.text_disabled
|
||||
selectionColor: control.palette.highlight
|
||||
selectedTextColor: control.palette.highlightedText
|
||||
|
||||
onEditingFinished: root.editingFinished()
|
||||
|
||||
wrapMode: TextInput.Wrap
|
||||
|
||||
// enforcing default focus here within component
|
||||
focus: root.focus
|
||||
|
||||
KeyNavigation.priority: root.KeyNavigation.priority
|
||||
KeyNavigation.backtab: root.KeyNavigation.backtab
|
||||
KeyNavigation.tab: root.KeyNavigation.tab
|
||||
KeyNavigation.up: root.KeyNavigation.up
|
||||
KeyNavigation.down: root.KeyNavigation.down
|
||||
KeyNavigation.left: root.KeyNavigation.left
|
||||
KeyNavigation.right: root.KeyNavigation.right
|
||||
|
||||
selectByMouse: true
|
||||
|
||||
cursorDelegate: Rectangle {
|
||||
id: cursor
|
||||
width: 1
|
||||
color: root.colorScheme.interaction_norm
|
||||
visible: control.activeFocus && !control.readOnly && control.selectionStart === control.selectionEnd
|
||||
|
||||
Connections {
|
||||
target: control
|
||||
onCursorPositionChanged: {
|
||||
// keep a moving cursor visible
|
||||
cursor.opacity = 1
|
||||
timer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
running: control.activeFocus && !control.readOnly
|
||||
repeat: true
|
||||
interval: Qt.styleHints.cursorFlashTime / 2
|
||||
onTriggered: cursor.opacity = !cursor.opacity ? 1 : 0
|
||||
// force the cursor visible when gaining focus
|
||||
onRunningChanged: cursor.opacity = 1
|
||||
}
|
||||
}
|
||||
|
||||
PlaceholderText {
|
||||
id: placeholder
|
||||
x: control.leftPadding
|
||||
y: control.topPadding
|
||||
width: control.width - (control.leftPadding + control.rightPadding)
|
||||
height: control.height - (control.topPadding + control.bottomPadding)
|
||||
|
||||
text: control.placeholderText
|
||||
font: control.font
|
||||
color: control.placeholderTextColor
|
||||
verticalAlignment: control.verticalAlignment
|
||||
visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
|
||||
elide: Text.ElideRight
|
||||
renderType: control.renderType
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
|
||||
radius: Style.input_radius
|
||||
visible: true
|
||||
color: root.colorScheme.background_norm
|
||||
border.color: {
|
||||
if (!control.enabled) {
|
||||
return root.colorScheme.field_disabled
|
||||
}
|
||||
|
||||
if (control.activeFocus) {
|
||||
return root.colorScheme.interaction_norm
|
||||
}
|
||||
|
||||
if (root.error) {
|
||||
return root.colorScheme.signal_danger
|
||||
}
|
||||
|
||||
if (control.hovered) {
|
||||
return root.colorScheme.field_hover
|
||||
}
|
||||
|
||||
return root.colorScheme.field_norm
|
||||
}
|
||||
border.width: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: footerLayout
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
ColorImage {
|
||||
id: errorIcon
|
||||
|
||||
Layout.rightMargin: 4
|
||||
|
||||
visible: root.error && (assistiveText.text.length > 0)
|
||||
source: "../icons/ic-exclamation-circle-filled.svg"
|
||||
color: root.colorScheme.signal_danger
|
||||
height: assistiveText.height
|
||||
sourceSize.height: assistiveText.height
|
||||
}
|
||||
|
||||
Proton.Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: assistiveText
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: root.error ? root.errorString : root.assistiveText
|
||||
|
||||
color: {
|
||||
if (!root.enabled) {
|
||||
return root.colorScheme.text_disabled
|
||||
}
|
||||
|
||||
if (root.error) {
|
||||
return root.colorScheme.signal_danger
|
||||
}
|
||||
|
||||
return root.colorScheme.text_weak
|
||||
}
|
||||
|
||||
type: root.error ? Proton.Label.LabelType.Caption_semibold : Proton.Label.LabelType.Caption
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property bool validateOnEditingFinished: true
|
||||
onEditingFinished: {
|
||||
if (!validateOnEditingFinished) {
|
||||
return
|
||||
}
|
||||
validate()
|
||||
}
|
||||
|
||||
function validate() {
|
||||
if (validator === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
var error = validator(text)
|
||||
|
||||
if (error) {
|
||||
root.error = true
|
||||
root.errorString = error
|
||||
} else {
|
||||
root.error = false
|
||||
root.errorString = ""
|
||||
}
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
root.error = false
|
||||
root.errorString = ""
|
||||
}
|
||||
}
|
||||
381
internal/frontend/qt6/qml/Proton/TextField.qml
Normal file
@ -0,0 +1,381 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
import QtQuick.Templates 2.12 as T
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import "." as Proton
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
property ColorScheme colorScheme
|
||||
|
||||
property alias background: control.background
|
||||
property alias bottomInset: control.bottomInset
|
||||
property alias focusReason: control.focusReason
|
||||
property alias hoverEnabled: control.hoverEnabled
|
||||
property alias hovered: control.hovered
|
||||
property alias implicitBackgroundHeight: control.implicitBackgroundHeight
|
||||
property alias implicitBackgroundWidth: control.implicitBackgroundWidth
|
||||
property alias leftInset: control.leftInset
|
||||
property alias palette: control.palette
|
||||
property alias placeholderText: control.placeholderText
|
||||
property alias placeholderTextColor: control.placeholderTextColor
|
||||
property alias rightInset: control.rightInset
|
||||
property alias topInset: control.topInset
|
||||
property alias acceptableInput: control.acceptableInput
|
||||
property alias activeFocusOnPress: control.activeFocusOnPress
|
||||
property alias autoScroll: control.autoScroll
|
||||
property alias bottomPadding: control.bottomPadding
|
||||
property alias canPaste: control.canPaste
|
||||
property alias canRedo: control.canRedo
|
||||
property alias canUndo: control.canUndo
|
||||
property alias color: control.color
|
||||
//property alias contentHeight: control.contentHeight
|
||||
//property alias contentWidth: control.contentWidth
|
||||
property alias cursorDelegate: control.cursorDelegate
|
||||
property alias cursorPosition: control.cursorPosition
|
||||
property alias cursorRectangle: control.cursorRectangle
|
||||
property alias cursorVisible: control.cursorVisible
|
||||
property alias displayText: control.displayText
|
||||
property alias effectiveHorizontalAlignment: control.effectiveHorizontalAlignment
|
||||
property alias font: control.font
|
||||
property alias horizontalAlignment: control.horizontalAlignment
|
||||
property alias inputMask: control.inputMask
|
||||
property alias inputMethodComposing: control.inputMethodComposing
|
||||
property alias inputMethodHints: control.inputMethodHints
|
||||
property alias leftPadding: control.leftPadding
|
||||
property alias length: control.length
|
||||
property alias maximumLength: control.maximumLength
|
||||
property alias mouseSelectionMode: control.mouseSelectionMode
|
||||
property alias overwriteMode: control.overwriteMode
|
||||
property alias padding: control.padding
|
||||
property alias passwordCharacter: control.passwordCharacter
|
||||
property alias passwordMaskDelay: control.passwordMaskDelay
|
||||
property alias persistentSelection: control.persistentSelection
|
||||
property alias preeditText: control.preeditText
|
||||
property alias readOnly: control.readOnly
|
||||
property alias renderType: control.renderType
|
||||
property alias rightPadding: control.rightPadding
|
||||
property alias selectByMouse: control.selectByMouse
|
||||
property alias selectedText: control.selectedText
|
||||
property alias selectedTextColor: control.selectedTextColor
|
||||
property alias selectionColor: control.selectionColor
|
||||
property alias selectionEnd: control.selectionEnd
|
||||
property alias selectionStart: control.selectionStart
|
||||
property alias text: control.text
|
||||
// We are using our own type of validators. It should be a function
|
||||
// returning an error string in case of error and undefined if no error
|
||||
property var validator
|
||||
property alias verticalAlignment: control.verticalAlignment
|
||||
property alias wrapMode: control.wrapMode
|
||||
|
||||
implicitWidth: children[0].implicitWidth
|
||||
implicitHeight: children[0].implicitHeight
|
||||
|
||||
property alias label: label.text
|
||||
property alias hint: hint.text
|
||||
property string assistiveText
|
||||
property string errorString
|
||||
|
||||
property int echoMode: TextInput.Normal
|
||||
|
||||
property bool error: false
|
||||
|
||||
signal accepted()
|
||||
signal editingFinished()
|
||||
signal textEdited()
|
||||
|
||||
function clear() { control.clear() }
|
||||
function copy() { control.copy() }
|
||||
function cut() { control.cut() }
|
||||
function deselect() { control.deselect() }
|
||||
function ensureVisible(position) { control.ensureVisible(position) }
|
||||
function getText(start, end) { control.getText(start, end) }
|
||||
function insert(position, text) { control.insert(position, text) }
|
||||
function isRightToLeft(start, end) { control.isRightToLeft(start, end) }
|
||||
function moveCursorSelection(position, mode) { control.moveCursorSelection(position, mode) }
|
||||
function paste() { control.paste() }
|
||||
function positionAt(x, y, position) { control.positionAt(x, y, position) }
|
||||
function positionToRectangle(pos) { control.positionToRectangle(pos) }
|
||||
function redo() { control.redo() }
|
||||
function remove(start, end) { control.remove(start, end) }
|
||||
function select(start, end) { control.select(start, end) }
|
||||
function selectAll() { control.selectAll() }
|
||||
function selectWord() { control.selectWord() }
|
||||
function undo() { control.undo() }
|
||||
function forceActiveFocus() { control.forceActiveFocus() }
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
Proton.Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: label
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
type: Proton.Label.LabelType.Body_semibold
|
||||
}
|
||||
|
||||
Proton.Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: hint
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
color: root.enabled ? root.colorScheme.text_weak : root.colorScheme.text_disabled
|
||||
horizontalAlignment: Text.AlignRight
|
||||
type: Proton.Label.LabelType.Caption
|
||||
}
|
||||
}
|
||||
|
||||
// Background is moved away from within control to cover eye button as well.
|
||||
// In case it will remain as control background property - control's width
|
||||
// will be adjusted to background's width making text field and eye button overlap
|
||||
Rectangle {
|
||||
id: background
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
radius: Style.input_radius
|
||||
visible: true
|
||||
color: root.colorScheme.background_norm
|
||||
border.color: {
|
||||
if (!control.enabled) {
|
||||
return root.colorScheme.field_disabled
|
||||
}
|
||||
|
||||
if (control.activeFocus) {
|
||||
return root.colorScheme.interaction_norm
|
||||
}
|
||||
|
||||
if (root.error) {
|
||||
return root.colorScheme.signal_danger
|
||||
}
|
||||
|
||||
if (control.hovered) {
|
||||
return root.colorScheme.field_hover
|
||||
}
|
||||
|
||||
return root.colorScheme.field_norm
|
||||
}
|
||||
border.width: 1
|
||||
|
||||
implicitWidth: children[0].implicitWidth
|
||||
implicitHeight: children[0].implicitHeight
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
T.TextField {
|
||||
id: control
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
implicitWidth: implicitBackgroundWidth + leftInset + rightInset
|
||||
|| Math.max(contentWidth, placeholder.implicitWidth) + leftPadding + rightPadding
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
|
||||
contentHeight + topPadding + bottomPadding,
|
||||
placeholder.implicitHeight + topPadding + bottomPadding)
|
||||
|
||||
topPadding: 8
|
||||
bottomPadding: 8
|
||||
leftPadding: 12
|
||||
rightPadding: 12
|
||||
|
||||
font.family: Style.font_family
|
||||
font.weight: Style.fontWeight_400
|
||||
font.pixelSize: Style.body_font_size
|
||||
font.letterSpacing: Style.body_letter_spacing
|
||||
|
||||
color: control.enabled ? root.colorScheme.text_norm : root.colorScheme.text_disabled
|
||||
placeholderTextColor: control.enabled ? root.colorScheme.text_hint : root.colorScheme.text_disabled
|
||||
selectionColor: control.palette.highlight
|
||||
selectedTextColor: control.palette.highlightedText
|
||||
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
|
||||
echoMode: eyeButton.checked ? TextInput.Normal : root.echoMode
|
||||
|
||||
// enforcing default focus here within component
|
||||
focus: true
|
||||
|
||||
KeyNavigation.priority: root.KeyNavigation.priority
|
||||
KeyNavigation.backtab: root.KeyNavigation.backtab
|
||||
KeyNavigation.tab: root.KeyNavigation.tab
|
||||
KeyNavigation.up: root.KeyNavigation.up
|
||||
KeyNavigation.down: root.KeyNavigation.down
|
||||
KeyNavigation.left: root.KeyNavigation.left
|
||||
KeyNavigation.right: root.KeyNavigation.right
|
||||
|
||||
selectByMouse: true
|
||||
|
||||
cursorDelegate: Rectangle {
|
||||
id: cursor
|
||||
width: 1
|
||||
color: root.colorScheme.interaction_norm
|
||||
visible: control.activeFocus && !control.readOnly && control.selectionStart === control.selectionEnd
|
||||
|
||||
Connections {
|
||||
target: control
|
||||
onCursorPositionChanged: {
|
||||
// keep a moving cursor visible
|
||||
cursor.opacity = 1
|
||||
timer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
running: control.activeFocus && !control.readOnly
|
||||
repeat: true
|
||||
interval: Qt.styleHints.cursorFlashTime / 2
|
||||
onTriggered: cursor.opacity = !cursor.opacity ? 1 : 0
|
||||
// force the cursor visible when gaining focus
|
||||
onRunningChanged: cursor.opacity = 1
|
||||
}
|
||||
}
|
||||
|
||||
PlaceholderText {
|
||||
id: placeholder
|
||||
x: control.leftPadding
|
||||
y: control.topPadding
|
||||
width: control.width - (control.leftPadding + control.rightPadding)
|
||||
height: control.height - (control.topPadding + control.bottomPadding)
|
||||
|
||||
text: control.placeholderText
|
||||
font: control.font
|
||||
color: control.placeholderTextColor
|
||||
verticalAlignment: control.verticalAlignment
|
||||
visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
|
||||
elide: Text.ElideRight
|
||||
renderType: control.renderType
|
||||
}
|
||||
|
||||
background: Item {
|
||||
implicitWidth: 80
|
||||
implicitHeight: 36
|
||||
visible: false
|
||||
}
|
||||
|
||||
onAccepted: {
|
||||
root.accepted()
|
||||
}
|
||||
onEditingFinished: {
|
||||
root.editingFinished()
|
||||
}
|
||||
onTextEdited: {
|
||||
root.textEdited()
|
||||
}
|
||||
}
|
||||
|
||||
Proton.Button {
|
||||
colorScheme: root.colorScheme
|
||||
id: eyeButton
|
||||
|
||||
Layout.fillHeight: true
|
||||
|
||||
visible: root.echoMode === TextInput.Password
|
||||
icon.color: control.color
|
||||
checkable: true
|
||||
icon.source: checked ? "../icons/ic-eye-slash.svg" : "../icons/ic-eye.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
ColorImage {
|
||||
id: errorIcon
|
||||
|
||||
Layout.rightMargin: 4
|
||||
|
||||
visible: root.error && (assistiveText.text.length > 0)
|
||||
source: "../icons/ic-exclamation-circle-filled.svg"
|
||||
color: root.colorScheme.signal_danger
|
||||
height: assistiveText.height
|
||||
sourceSize.height: assistiveText.height
|
||||
}
|
||||
|
||||
Proton.Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: assistiveText
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: root.error ? root.errorString : root.assistiveText
|
||||
|
||||
color: {
|
||||
if (!root.enabled) {
|
||||
return root.colorScheme.text_disabled
|
||||
}
|
||||
|
||||
if (root.error) {
|
||||
return root.colorScheme.signal_danger
|
||||
}
|
||||
|
||||
return root.colorScheme.text_weak
|
||||
}
|
||||
|
||||
type: root.error ? Proton.Label.LabelType.Caption_semibold : Proton.Label.LabelType.Caption
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property bool validateOnEditingFinished: true
|
||||
onEditingFinished: {
|
||||
if (!validateOnEditingFinished) {
|
||||
return
|
||||
}
|
||||
validate()
|
||||
}
|
||||
|
||||
function validate() {
|
||||
if (validator === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
var error = validator(text)
|
||||
|
||||
if (error) {
|
||||
root.error = true
|
||||
root.errorString = error
|
||||
} else {
|
||||
root.error = false
|
||||
root.errorString = ""
|
||||
}
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
root.error = false
|
||||
root.errorString = ""
|
||||
}
|
||||
}
|
||||
113
internal/frontend/qt6/qml/Proton/Toggle.qml
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Controls.impl 2.13
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property var colorScheme
|
||||
property bool checked
|
||||
property bool hovered
|
||||
property bool loading
|
||||
|
||||
signal clicked
|
||||
|
||||
property bool _disabled: !enabled
|
||||
|
||||
implicitHeight: children[0].implicitHeight
|
||||
implicitWidth: children[0].implicitWidth
|
||||
|
||||
Rectangle {
|
||||
id: indicator
|
||||
implicitWidth: 40
|
||||
implicitHeight: 24
|
||||
|
||||
radius: width/2
|
||||
color: {
|
||||
if (root.loading) return "transparent"
|
||||
if (root._disabled) return root.colorScheme.background_strong
|
||||
return root.colorScheme.background_norm
|
||||
}
|
||||
border {
|
||||
width: 1
|
||||
color: (root._disabled || root.loading) ? "transparent" : colorScheme.field_norm
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: indicator.verticalCenter
|
||||
anchors.left: indicator.left
|
||||
anchors.leftMargin: root.checked ? 16 : 0
|
||||
width: 24
|
||||
height: 24
|
||||
radius: width/2
|
||||
color: {
|
||||
if (root.loading) return "transparent"
|
||||
if (root._disabled) return root.colorScheme.field_disabled
|
||||
|
||||
if (root.checked) {
|
||||
if (root.hovered) return root.colorScheme.interaction_norm_hover
|
||||
return root.colorScheme.interaction_norm
|
||||
} else {
|
||||
if (root.hovered) return root.colorScheme.field_hover
|
||||
return root.colorScheme.field_norm
|
||||
}
|
||||
}
|
||||
|
||||
ColorImage {
|
||||
anchors.centerIn: parent
|
||||
source: "../icons/ic-check.svg"
|
||||
color: root.colorScheme.background_norm
|
||||
height: root.colorScheme.body_font_size
|
||||
sourceSize.height: root.colorScheme.body_font_size
|
||||
visible: root.checked
|
||||
}
|
||||
}
|
||||
|
||||
ColorImage {
|
||||
id: loader
|
||||
anchors.centerIn: parent
|
||||
source: "../icons/Loader_16.svg"
|
||||
color: root.colorScheme.text_norm
|
||||
height: root.colorScheme.body_font_size
|
||||
sourceSize.height: root.colorScheme.body_font_size
|
||||
visible: root.loading
|
||||
|
||||
RotationAnimation {
|
||||
target: loader
|
||||
loops: Animation.Infinite
|
||||
duration: 1000
|
||||
from: 0
|
||||
to: 360
|
||||
direction: RotationAnimation.Clockwise
|
||||
running: root.loading
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: indicator
|
||||
hoverEnabled: true
|
||||
onEntered: {root.hovered = true }
|
||||
onExited: {root.hovered = false }
|
||||
onClicked: { if (root.enabled) root.clicked();}
|
||||
onPressed: {root.hovered = true }
|
||||
onReleased: { root.hovered = containsMouse }
|
||||
}
|
||||
}
|
||||
}
|
||||
37
internal/frontend/qt6/qml/Proton/qmldir
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright (c) 2021 Proton AG
|
||||
#
|
||||
# This file is part of Proton Mail Bridge.
|
||||
#
|
||||
# Proton Mail 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.
|
||||
#
|
||||
# Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
module QQtQuick.Controls.Proton
|
||||
depends QtQuick.Controls 2.12
|
||||
|
||||
singleton ProtonStyle 4.0 Style.qml
|
||||
ColorScheme 4.0 ColorScheme.qml
|
||||
|
||||
ApplicationWindow 4.0 ApplicationWindow.qml
|
||||
Button 4.0 Button.qml
|
||||
CheckBox 4.0 CheckBox.qml
|
||||
ComboBox 4.0 ComboBox.qml
|
||||
Dialog 4.0 Dialog.qml
|
||||
Label 4.0 Label.qml
|
||||
Menu 4.0 Menu.qml
|
||||
MenuItem 4.0 MenuItem.qml
|
||||
Popup 4.0 Popup.qml
|
||||
RadioButton 4.0 RadioButton.qml
|
||||
Switch 4.0 Switch.qml
|
||||
TextArea 4.0 TextArea.qml
|
||||
TextField 4.0 TextField.qml
|
||||
Toggle 4.0 Toggle.qml
|
||||
120
internal/frontend/qt6/qml/SMTPSettings.qml
Normal file
@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Controls.impl 2.13
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
SettingsView {
|
||||
id: root
|
||||
|
||||
fillHeight: false
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("SMTP connection mode")
|
||||
type: Label.Heading
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Changes require reconfiguration of email client. Bridge will automatically restart.")
|
||||
type: Label.Body
|
||||
color: root.colorScheme.text_weak
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: this.parent.Layout.maximumWidth
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 16
|
||||
|
||||
ButtonGroup{ id: protocolSelection }
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("SMTP connection security")
|
||||
}
|
||||
|
||||
RadioButton {
|
||||
id: sslButton
|
||||
colorScheme: root.colorScheme
|
||||
ButtonGroup.group: protocolSelection
|
||||
text: qsTr("SSL")
|
||||
}
|
||||
|
||||
RadioButton {
|
||||
id: starttlsButton
|
||||
colorScheme: root.colorScheme
|
||||
ButtonGroup.group: protocolSelection
|
||||
text: qsTr("STARTTLS")
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: root.colorScheme.border_weak
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
|
||||
Button {
|
||||
id: submitButton
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Save and restart")
|
||||
onClicked: {
|
||||
submitButton.loading = true
|
||||
root.submit()
|
||||
}
|
||||
|
||||
enabled: sslButton.checked !== root.backend.useSSLforSMTP
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Cancel")
|
||||
onClicked: root.back()
|
||||
secondary: true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.backend
|
||||
|
||||
onToggleUseSSLFinished: submitButton.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
function submit(){
|
||||
submitButton.loading = true
|
||||
root.backend.toggleUseSSLforSMTP(sslButton.checked)
|
||||
}
|
||||
|
||||
function setDefaultValues(){
|
||||
sslButton.checked = root.backend.useSSLforSMTP
|
||||
starttlsButton.checked = !root.backend.useSSLforSMTP
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
root.setDefaultValues()
|
||||
}
|
||||
}
|
||||
118
internal/frontend/qt6/qml/SettingsItem.qml
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property var colorScheme
|
||||
|
||||
property string text: "Text"
|
||||
property string actionText: "Action"
|
||||
property string actionIcon: ""
|
||||
property string description: "Lorem ipsum dolor sit amet"
|
||||
property alias descriptionWrap: descriptionLabel.wrapMode
|
||||
property var type: SettingsItem.ActionType.Toggle
|
||||
|
||||
property bool checked: true
|
||||
property bool loading: false
|
||||
property bool showSeparator: true
|
||||
|
||||
property var _bottomMargin: 20
|
||||
property var _lineWidth: 1
|
||||
property var _toggleTopMargin: 6
|
||||
|
||||
signal clicked
|
||||
|
||||
enum ActionType {
|
||||
Toggle = 1, Button = 2, PrimaryButton = 3
|
||||
}
|
||||
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 16
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: root._bottomMargin
|
||||
|
||||
spacing: 4
|
||||
|
||||
Label {
|
||||
id: mainLabel
|
||||
colorScheme: root.colorScheme
|
||||
text: root.text
|
||||
type: Label.Body_semibold
|
||||
}
|
||||
|
||||
Label {
|
||||
id: descriptionLabel
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
Layout.preferredWidth: parent.width
|
||||
|
||||
wrapMode: Text.WordWrap
|
||||
colorScheme: root.colorScheme
|
||||
text: root.description
|
||||
color: root.colorScheme.text_weak
|
||||
}
|
||||
}
|
||||
|
||||
Toggle {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.topMargin: root._toggleTopMargin
|
||||
id: toggle
|
||||
colorScheme: root.colorScheme
|
||||
visible: root.type === SettingsItem.ActionType.Toggle
|
||||
|
||||
checked: root.checked
|
||||
loading: root.loading
|
||||
onClicked: { if (!root.loading) root.clicked() }
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
id: button
|
||||
colorScheme: root.colorScheme
|
||||
visible: root.type === SettingsItem.Button || root.type === SettingsItem.PrimaryButton
|
||||
text: root.actionText + (root.actionIcon != "" ? " " : "")
|
||||
loading: root.loading
|
||||
icon.source: root.actionIcon
|
||||
onClicked: { if (!root.loading) root.clicked() }
|
||||
secondary: root.type !== SettingsItem.PrimaryButton
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: root.left
|
||||
anchors.right: root.right
|
||||
anchors.bottom: root.bottom
|
||||
color: colorScheme.border_weak
|
||||
height: root._lineWidth
|
||||
visible: root.showSeparator
|
||||
}
|
||||
}
|
||||
99
internal/frontend/qt6/qml/SettingsView.qml
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Controls.impl 2.13
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var colorScheme
|
||||
property var backend
|
||||
default property alias items: content.children
|
||||
|
||||
signal back()
|
||||
|
||||
property int _leftMargin: 64
|
||||
property int _rightMargin: 64
|
||||
property int _topMargin: 32
|
||||
property int _bottomMargin: 32
|
||||
property int _spacing: 20
|
||||
|
||||
// fillHeight indicates whether the SettingsView should fill all available explicit height set
|
||||
property bool fillHeight: false
|
||||
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
clip: true
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
// can't use parent here because parent is not ScrollView (Flickable inside contentItem inside ScrollView)
|
||||
width: scrollView.availableWidth
|
||||
height: scrollView.availableHeight
|
||||
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
// do not set implicitWidth because implicit width of ColumnLayout will be equal to maximum implicit width of
|
||||
// internal items. And if one of internal items would be a Text or Label - implicit width of those is always
|
||||
// equal to non-wrapped text (i.e. one line only). That will lead to enabling horizontal scroll when not needed
|
||||
implicitWidth: width
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
spacing: root._spacing
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
Layout.topMargin: root._topMargin
|
||||
Layout.bottomMargin: root._bottomMargin
|
||||
Layout.leftMargin: root._leftMargin
|
||||
Layout.rightMargin: root._rightMargin
|
||||
}
|
||||
|
||||
Item {
|
||||
id: filler
|
||||
Layout.fillHeight: true
|
||||
visible: !root.fillHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: backButton
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
topMargin: root._topMargin
|
||||
leftMargin: (root._leftMargin-backButton.width) / 2
|
||||
}
|
||||
colorScheme: root.colorScheme
|
||||
onClicked: root.back()
|
||||
icon.source: "icons/ic-arrow-left.svg"
|
||||
secondary: true
|
||||
horizontalPadding: 8
|
||||
}
|
||||
}
|
||||
317
internal/frontend/qt6/qml/SetupGuide.qml
Normal file
@ -0,0 +1,317 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
Item {
|
||||
id:root
|
||||
|
||||
property ColorScheme colorScheme
|
||||
property var backend
|
||||
property var user
|
||||
property string address
|
||||
|
||||
signal dismissed()
|
||||
signal finished()
|
||||
|
||||
implicitHeight: children[0].implicitHeight
|
||||
implicitWidth: children[0].implicitWidth
|
||||
|
||||
|
||||
ListModel {
|
||||
id: clients
|
||||
property string name : "Apple Mail"
|
||||
property string iconSource : "./icons/ic-apple-mail.svg"
|
||||
property bool haveAutoSetup: true
|
||||
property string link: "https://protonmail.com/bridge/applemail"
|
||||
|
||||
Component.onCompleted : {
|
||||
if (root.backend.goos == "darwin") {
|
||||
append({
|
||||
"name" : "Apple Mail",
|
||||
"iconSource" : "./icons/ic-apple-mail.svg",
|
||||
"haveAutoSetup" : true,
|
||||
"link" : "https://protonmail.com/bridge/applemail"
|
||||
})
|
||||
append({
|
||||
"name" : "Microsoft Outlook",
|
||||
"iconSource" : "./icons/ic-microsoft-outlook.svg",
|
||||
"haveAutoSetup" : false,
|
||||
"link" : "https://protonmail.com/bridge/outlook2019-mac"
|
||||
})
|
||||
}
|
||||
if (root.backend.goos == "windows") {
|
||||
append({
|
||||
"name" : "Microsoft Outlook",
|
||||
"iconSource" : "./icons/ic-microsoft-outlook.svg",
|
||||
"haveAutoSetup" : false,
|
||||
"link" : "https://protonmail.com/bridge/outlook2019"
|
||||
})
|
||||
}
|
||||
|
||||
append({
|
||||
"name" : "Mozilla Thunderbird",
|
||||
"iconSource" : "./icons/ic-mozilla-thunderbird.svg",
|
||||
"haveAutoSetup" : false,
|
||||
"link" : "https://protonmail.com/bridge/thunderbird"
|
||||
})
|
||||
|
||||
append({
|
||||
"name" : "Other",
|
||||
"iconSource" : "./icons/ic-other-mail-clients.svg",
|
||||
"haveAutoSetup" : false,
|
||||
"link" : "https://protonmail.com/bridge/clients"
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: root
|
||||
color: root.colorScheme.background_norm
|
||||
}
|
||||
|
||||
StackLayout {
|
||||
id: guidePages
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 80
|
||||
anchors.rightMargin: 80
|
||||
anchors.topMargin: 30
|
||||
anchors.bottomMargin: 70
|
||||
|
||||
|
||||
ColumnLayout { // 0: Client selection
|
||||
id: clientView
|
||||
Layout.fillHeight: true
|
||||
|
||||
property int columnWidth: 268
|
||||
|
||||
spacing: 8
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Setting up email client")
|
||||
type: Label.LabelType.Heading
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: address
|
||||
color: root.colorScheme.text_weak
|
||||
type: Label.LabelType.Lead
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.topMargin: 32-clientView.spacing
|
||||
spacing: 24
|
||||
|
||||
ColumnLayout {
|
||||
id: clientColumn
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
Label {
|
||||
id: labelA
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Choose an email client")
|
||||
type: Label.LabelType.Body_semibold
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: clientList
|
||||
Layout.fillHeight: true
|
||||
width: clientView.columnWidth
|
||||
|
||||
model: clients
|
||||
|
||||
highlight: Rectangle {
|
||||
color: root.colorScheme.interaction_default_active
|
||||
radius: ProtonStyle.context_item_radius
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: clientRow.width
|
||||
implicitHeight: clientRow.height
|
||||
|
||||
ColumnLayout {
|
||||
id: clientRow
|
||||
width: clientList.width
|
||||
|
||||
RowLayout {
|
||||
Layout.topMargin: 12
|
||||
Layout.bottomMargin: 12
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
|
||||
ColorImage {
|
||||
source: model.iconSource
|
||||
height: 36
|
||||
sourceSize.height: 36
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
Layout.leftMargin: 12
|
||||
text: model.name
|
||||
type: Label.LabelType.Body
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: root.colorScheme.border_weak
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
clientList.currentIndex = index
|
||||
if (!model.haveAutoSetup) {
|
||||
root.setupAction(1,index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: actionColumn
|
||||
visible: clientList.currentIndex >= 0 && clients.get(clientList.currentIndex).haveAutoSetup
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Choose configuration mode")
|
||||
type: Label.LabelType.Body_semibold
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: actionList
|
||||
Layout.fillHeight: true
|
||||
width: clientView.columnWidth
|
||||
|
||||
model: [
|
||||
qsTr("Configure automatically"),
|
||||
qsTr("Configure manually"),
|
||||
]
|
||||
|
||||
highlight: Rectangle {
|
||||
color: root.colorScheme.interaction_default_active
|
||||
radius: ProtonStyle.context_item_radius
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
implicitWidth: children[0].width
|
||||
implicitHeight: children[0].height
|
||||
|
||||
ColumnLayout {
|
||||
width: actionList.width
|
||||
|
||||
Label {
|
||||
Layout.topMargin: 20
|
||||
Layout.bottomMargin: 20
|
||||
Layout.leftMargin: 16
|
||||
Layout.rightMargin: 16
|
||||
colorScheme: root.colorScheme
|
||||
text: modelData
|
||||
type: Label.LabelType.Body
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: root.colorScheme.border_weak
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
actionList.currentIndex = index
|
||||
root.setupAction(index,clientList.currentIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Set up later")
|
||||
flat: true
|
||||
|
||||
onClicked: {
|
||||
root.setupAction(-1,-1)
|
||||
if (user) {
|
||||
user.setupGuideSeen = true
|
||||
}
|
||||
root.dismissed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setupAction(actionID,clientID){
|
||||
if (user) {
|
||||
user.setupGuideSeen = true
|
||||
}
|
||||
|
||||
switch (actionID) {
|
||||
case -1: root.dismissed(); break; // dismiss
|
||||
case 0: // automatic
|
||||
if (user) {
|
||||
switch (clientID) {
|
||||
case 0:
|
||||
root.user.configureAppleMail(root.address)
|
||||
break;
|
||||
}
|
||||
}
|
||||
root.finished()
|
||||
break;
|
||||
case 1: // manual
|
||||
var clientObj = clients.get(clientID)
|
||||
if (clientObj != undefined && clientObj.link != "" ) {
|
||||
Qt.openUrlExternally(clientObj.link)
|
||||
} else {
|
||||
console.log("unexpected client index", actionID, clientID)
|
||||
}
|
||||
root.finished();
|
||||
break;
|
||||
default:
|
||||
console.log("unexpected client setup action", actionID, clientID)
|
||||
}
|
||||
}
|
||||
|
||||
function reset(){
|
||||
guidePages.currentIndex = 0
|
||||
clientList.currentIndex = -1
|
||||
actionList.currentIndex = -1
|
||||
}
|
||||
}
|
||||
457
internal/frontend/qt6/qml/SignIn.qml
Normal file
@ -0,0 +1,457 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property ColorScheme colorScheme
|
||||
|
||||
function reset() {
|
||||
stackLayout.currentIndex = 0
|
||||
loginNormalLayout.reset()
|
||||
login2FALayout.reset()
|
||||
login2PasswordLayout.reset()
|
||||
|
||||
}
|
||||
|
||||
function abort() {
|
||||
root.reset()
|
||||
root.backend.loginAbort(usernameTextField.text)
|
||||
}
|
||||
|
||||
implicitHeight: children[0].implicitHeight
|
||||
implicitWidth: children[0].implicitWidth
|
||||
|
||||
property var backend
|
||||
|
||||
property alias username: usernameTextField.text
|
||||
state: "Page 1"
|
||||
|
||||
property alias currentIndex: stackLayout.currentIndex
|
||||
|
||||
StackLayout {
|
||||
id: stackLayout
|
||||
anchors.fill: parent
|
||||
|
||||
function loginFailed() {
|
||||
signInButton.loading = false
|
||||
|
||||
usernameTextField.enabled = true
|
||||
usernameTextField.error = true
|
||||
|
||||
passwordTextField.enabled = true
|
||||
passwordTextField.error = true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.backend
|
||||
|
||||
onLoginUsernamePasswordError: {
|
||||
console.assert(stackLayout.currentIndex == 0, "Unexpected loginUsernamePasswordError")
|
||||
console.assert(signInButton.loading == true, "Unexpected loginUsernamePasswordError")
|
||||
|
||||
stackLayout.loginFailed()
|
||||
if (errorMsg!="") errorLabel.text = errorMsg
|
||||
else errorLabel.text = qsTr("Incorrect login credentials")
|
||||
}
|
||||
|
||||
onLoginFreeUserError: {
|
||||
console.assert(stackLayout.currentIndex == 0, "Unexpected loginFreeUserError")
|
||||
stackLayout.loginFailed()
|
||||
}
|
||||
|
||||
onLoginConnectionError: {
|
||||
if (stackLayout.currentIndex == 0 ) {
|
||||
stackLayout.loginFailed()
|
||||
}
|
||||
}
|
||||
|
||||
onLogin2FARequested: {
|
||||
console.assert(stackLayout.currentIndex == 0, "Unexpected login2FARequested")
|
||||
twoFactorUsernameLabel.text = username
|
||||
stackLayout.currentIndex = 1
|
||||
}
|
||||
onLogin2FAError: {
|
||||
console.assert(stackLayout.currentIndex == 1, "Unexpected login2FAError")
|
||||
|
||||
twoFAButton.loading = false
|
||||
|
||||
twoFactorPasswordTextField.enabled = true
|
||||
twoFactorPasswordTextField.error = true
|
||||
twoFactorPasswordTextField.errorString = qsTr("Your code is incorrect")
|
||||
}
|
||||
onLogin2FAErrorAbort: {
|
||||
console.assert(stackLayout.currentIndex == 1, "Unexpected login2FAErrorAbort")
|
||||
root.reset()
|
||||
errorLabel.text = qsTr("Incorrect login credentials. Please try again.")
|
||||
}
|
||||
|
||||
onLogin2PasswordRequested: {
|
||||
console.assert(stackLayout.currentIndex == 0 || stackLayout.currentIndex == 1, "Unexpected login2PasswordRequested")
|
||||
stackLayout.currentIndex = 2
|
||||
}
|
||||
onLogin2PasswordError: {
|
||||
console.assert(stackLayout.currentIndex == 2, "Unexpected login2PasswordError")
|
||||
|
||||
secondPasswordButton.loading = false
|
||||
|
||||
secondPasswordTextField.enabled = true
|
||||
secondPasswordTextField.error = true
|
||||
secondPasswordTextField.errorString = qsTr("Your mailbox password is incorrect")
|
||||
}
|
||||
onLogin2PasswordErrorAbort: {
|
||||
console.assert(stackLayout.currentIndex == 2, "Unexpected login2PasswordErrorAbort")
|
||||
root.reset()
|
||||
errorLabel.text = qsTr("Incorrect login credentials. Please try again.")
|
||||
}
|
||||
|
||||
onLoginFinished: {
|
||||
stackLayout.currentIndex = 0
|
||||
root.reset()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: loginNormalLayout
|
||||
|
||||
function reset() {
|
||||
signInButton.loading = false
|
||||
|
||||
errorLabel.text = ""
|
||||
|
||||
usernameTextField.enabled = true
|
||||
usernameTextField.error = false
|
||||
usernameTextField.errorString = ""
|
||||
|
||||
passwordTextField.enabled = true
|
||||
passwordTextField.error = false
|
||||
passwordTextField.errorString = ""
|
||||
passwordTextField.text = ""
|
||||
}
|
||||
|
||||
spacing: 0
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Sign in")
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 16
|
||||
type: Label.LabelType.Title
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: subTitle
|
||||
text: qsTr("Enter your Proton Account details.")
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 8
|
||||
color: root.colorScheme.text_weak
|
||||
type: Label.LabelType.Body
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 36
|
||||
|
||||
spacing: 0
|
||||
visible: errorLabel.text.length > 0
|
||||
|
||||
ColorImage {
|
||||
color: root.colorScheme.signal_danger
|
||||
source: "./icons/ic-exclamation-circle-filled.svg"
|
||||
height: errorLabel.height
|
||||
sourceSize.height: errorLabel.height
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: errorLabel
|
||||
Layout.leftMargin: 4
|
||||
color: root.colorScheme.signal_danger
|
||||
|
||||
type: root.error ? Label.LabelType.Caption_semibold : Label.LabelType.Caption
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
colorScheme: root.colorScheme
|
||||
id: usernameTextField
|
||||
label: qsTr("Username or email")
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
||||
onTextChanged: {
|
||||
// remove "invalid username / password error"
|
||||
if (error || errorLabel.text.length > 0) {
|
||||
errorLabel.text = ""
|
||||
usernameTextField.error = false
|
||||
passwordTextField.error = false
|
||||
}
|
||||
}
|
||||
|
||||
validator: function(str) {
|
||||
if (str.length === 0) {
|
||||
return qsTr("Enter username or email")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
onAccepted: passwordTextField.forceActiveFocus()
|
||||
}
|
||||
|
||||
TextField {
|
||||
colorScheme: root.colorScheme
|
||||
id: passwordTextField
|
||||
label: qsTr("Password")
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8
|
||||
echoMode: TextInput.Password
|
||||
|
||||
onTextChanged: {
|
||||
// remove "invalid username / password error"
|
||||
if (error || errorLabel.text.length > 0) {
|
||||
errorLabel.text = ""
|
||||
usernameTextField.error = false
|
||||
passwordTextField.error = false
|
||||
}
|
||||
}
|
||||
|
||||
validator: function(str) {
|
||||
if (str.length === 0) {
|
||||
return qsTr("Enter password")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
onAccepted: signInButton.checkAndSignIn()
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
id: signInButton
|
||||
text: qsTr("Sign in")
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
||||
|
||||
onClicked: checkAndSignIn()
|
||||
|
||||
function checkAndSignIn() {
|
||||
usernameTextField.validate()
|
||||
passwordTextField.validate()
|
||||
|
||||
if (usernameTextField.error || passwordTextField.error) {
|
||||
return
|
||||
}
|
||||
|
||||
usernameTextField.enabled = false
|
||||
passwordTextField.enabled = false
|
||||
|
||||
enabled = false
|
||||
loading = true
|
||||
|
||||
root.backend.login(usernameTextField.text, Qt.btoa(passwordTextField.text))
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
textFormat: Text.StyledText
|
||||
text: link("https://protonmail.com/signup", qsTr("Create or upgrade your account"))
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 24
|
||||
type: Label.LabelType.Body
|
||||
|
||||
onLinkActivated: {
|
||||
Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: login2FALayout
|
||||
|
||||
function reset() {
|
||||
twoFAButton.loading = false
|
||||
|
||||
twoFactorPasswordTextField.enabled = true
|
||||
twoFactorPasswordTextField.error = false
|
||||
twoFactorPasswordTextField.errorString = ""
|
||||
twoFactorPasswordTextField.text = ""
|
||||
}
|
||||
|
||||
spacing: 0
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Two-factor authentication")
|
||||
Layout.topMargin: 16
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
type: Label.LabelType.Heading
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: twoFactorUsernameLabel
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: 8
|
||||
type: Label.LabelType.Lead
|
||||
color: root.colorScheme.text_weak
|
||||
}
|
||||
|
||||
TextField {
|
||||
colorScheme: root.colorScheme
|
||||
id: twoFactorPasswordTextField
|
||||
label: qsTr("Two-factor code")
|
||||
assistiveText: qsTr("Enter the 6-digit code")
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 32
|
||||
|
||||
validator: function(str) {
|
||||
if (str.length === 0) {
|
||||
return qsTr("Enter username or email")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
id: twoFAButton
|
||||
text: loading ? qsTr("Authenticating") : qsTr("Authenticate")
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
||||
onClicked: {
|
||||
twoFactorPasswordTextField.validate()
|
||||
|
||||
if (twoFactorPasswordTextField.error) {
|
||||
return
|
||||
}
|
||||
|
||||
twoFactorPasswordTextField.enabled = false
|
||||
|
||||
enabled = false
|
||||
loading = true
|
||||
|
||||
root.backend.login2FA(usernameTextField.text, Qt.btoa(twoFactorPasswordTextField.text))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: login2PasswordLayout
|
||||
|
||||
function reset() {
|
||||
secondPasswordButton.loading = false
|
||||
|
||||
secondPasswordTextField.enabled = true
|
||||
secondPasswordTextField.error = false
|
||||
secondPasswordTextField.errorString = ""
|
||||
secondPasswordTextField.text = ""
|
||||
}
|
||||
|
||||
spacing: 0
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Unlock your mailbox")
|
||||
Layout.topMargin: 16
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
type: Label.LabelType.Heading
|
||||
}
|
||||
|
||||
TextField {
|
||||
colorScheme: root.colorScheme
|
||||
id: secondPasswordTextField
|
||||
label: qsTr("Mailbox password")
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 8 + implicitHeight + 24 + subTitle.implicitHeight
|
||||
echoMode: TextInput.Password
|
||||
|
||||
validator: function(str) {
|
||||
if (str.length === 0) {
|
||||
return qsTr("Enter username or email")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
id: secondPasswordButton
|
||||
text: loading ? qsTr("Unlocking") : qsTr("Unlock")
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 24
|
||||
|
||||
onClicked: {
|
||||
secondPasswordTextField.validate()
|
||||
|
||||
if (secondPasswordTextField.error) {
|
||||
return
|
||||
}
|
||||
|
||||
secondPasswordTextField.enabled = false
|
||||
|
||||
enabled = false
|
||||
loading = true
|
||||
|
||||
root.backend.login2Password(usernameTextField.text, Qt.btoa(secondPasswordTextField.text))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "Page 1"
|
||||
PropertyChanges {
|
||||
target: stackLayout
|
||||
currentIndex: 0
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "Page 2"
|
||||
PropertyChanges {
|
||||
target: stackLayout
|
||||
currentIndex: 1
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "Page 3"
|
||||
PropertyChanges {
|
||||
target: stackLayout
|
||||
currentIndex: 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
108
internal/frontend/qt6/qml/SplashScreen.qml
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
|
||||
property var backend
|
||||
|
||||
shouldShow: root.backend.showSplashScreen
|
||||
modal: true
|
||||
|
||||
topPadding : 0
|
||||
leftPadding : 0
|
||||
rightPadding : 0
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 20
|
||||
|
||||
Image {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
sourceSize.width: 400
|
||||
sourceSize.height: 225
|
||||
|
||||
Layout.preferredWidth: 400
|
||||
Layout.preferredHeight: 225
|
||||
|
||||
source: "./icons/img-splash.png"
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme;
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter;
|
||||
Layout.leftMargin: 24
|
||||
Layout.rightMargin: 24
|
||||
Layout.preferredWidth: 336
|
||||
|
||||
type: Label.Title
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Updated Proton, unified protection")
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter;
|
||||
Layout.preferredWidth: 336
|
||||
Layout.leftMargin: 24
|
||||
Layout.rightMargin: 24
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
type: Label.Body
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
textFormat: Text.StyledText
|
||||
text: qsTr("Introducing Proton’s refreshed look.<br/>") +
|
||||
qsTr("Many services, one mission. Welcome to an Internet where privacy is the default. ") +
|
||||
link("https://proton.me/news/updated-proton",qsTr("Learn More"))
|
||||
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 24
|
||||
Layout.rightMargin: 24
|
||||
colorScheme: root.colorScheme
|
||||
text: "Got it"
|
||||
onClicked: root.backend.showSplashScreen = false
|
||||
}
|
||||
|
||||
Image {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
sourceSize.width: 164
|
||||
sourceSize.height: 32
|
||||
|
||||
Layout.preferredWidth: 164
|
||||
Layout.preferredHeight: 32
|
||||
|
||||
source: "./icons/img-proton-logos.svg"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
112
internal/frontend/qt6/qml/Status.qml
Normal file
@ -0,0 +1,112 @@
|
||||
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Controls.impl 2.12
|
||||
|
||||
import Proton 4.0
|
||||
import Notifications 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var backend
|
||||
property var notifications
|
||||
property ColorScheme colorScheme
|
||||
|
||||
property int notificationWhitelist: NotificationFilter.FilterConsts.All
|
||||
property int notificationBlacklist: NotificationFilter.FilterConsts.None
|
||||
|
||||
readonly property Notification activeNotification: notificationFilter.topmost
|
||||
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
NotificationFilter {
|
||||
id: notificationFilter
|
||||
|
||||
source: root.notifications ? root.notifications.all : undefined
|
||||
whitelist: root.notificationWhitelist
|
||||
blacklist: root.notificationBlacklist
|
||||
|
||||
onTopmostChanged: {
|
||||
if (!topmost) {
|
||||
image.source = "./icons/ic-connected.svg"
|
||||
image.color = root.colorScheme.signal_success
|
||||
label.text = qsTr("Connected")
|
||||
label.color = root.colorScheme.signal_success
|
||||
return;
|
||||
}
|
||||
|
||||
image.source = topmost.icon
|
||||
label.text = topmost.brief
|
||||
|
||||
switch (topmost.type) {
|
||||
case Notification.NotificationType.Danger:
|
||||
image.color = root.colorScheme.signal_danger
|
||||
label.color = root.colorScheme.signal_danger
|
||||
break;
|
||||
case Notification.NotificationType.Warning:
|
||||
image.color = root.colorScheme.signal_warning
|
||||
label.color = root.colorScheme.signal_warning
|
||||
break;
|
||||
case Notification.NotificationType.Success:
|
||||
image.color = root.colorScheme.signal_success
|
||||
label.color = root.colorScheme.signal_success
|
||||
break;
|
||||
case Notification.NotificationType.Info:
|
||||
image.color = root.colorScheme.signal_info
|
||||
label.color = root.colorScheme.signal_info
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
|
||||
ColorImage {
|
||||
id: image
|
||||
width: 16
|
||||
height: 16
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
source: "./icons/ic-connected.svg"
|
||||
color: root.colorScheme.signal_success
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: label
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
text: qsTr("Connected")
|
||||
color: root.colorScheme.signal_success
|
||||
}
|
||||
}
|
||||
}
|
||||
328
internal/frontend/qt6/qml/StatusWindow.qml
Normal file
@ -0,0 +1,328 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Window 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.13
|
||||
|
||||
import Proton 4.0
|
||||
import Notifications 1.0
|
||||
|
||||
Window {
|
||||
id: root
|
||||
|
||||
height: contentLayout.implicitHeight
|
||||
width: contentLayout.implicitWidth
|
||||
|
||||
flags: (Qt.platform.os === "linux" ? Qt.Tool : 0) | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint | Qt.WindowStaysOnTopHint | Qt.WA_TranslucentBackground
|
||||
color: "transparent"
|
||||
|
||||
property ColorScheme colorScheme: ProtonStyle.currentStyle
|
||||
|
||||
property var backend
|
||||
property var notifications
|
||||
|
||||
signal showMainWindow()
|
||||
signal showHelp()
|
||||
signal showSettings()
|
||||
signal showSignIn(string username)
|
||||
signal quit()
|
||||
|
||||
ColumnLayout {
|
||||
id: contentLayout
|
||||
|
||||
Layout.minimumHeight: 201
|
||||
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
ColumnLayout {
|
||||
Layout.minimumWidth: 448
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
implicitHeight: 12
|
||||
Layout.fillWidth: true
|
||||
clip: true
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: parent.height * 2
|
||||
radius: ProtonStyle.dialog_radius
|
||||
|
||||
color: {
|
||||
if (!statusItem.activeNotification) {
|
||||
return root.colorScheme.signal_success
|
||||
}
|
||||
|
||||
switch (statusItem.activeNotification.type) {
|
||||
case Notification.NotificationType.Danger:
|
||||
return root.colorScheme.signal_danger
|
||||
case Notification.NotificationType.Warning:
|
||||
return root.colorScheme.signal_warning
|
||||
case Notification.NotificationType.Success:
|
||||
return root.colorScheme.signal_success
|
||||
case Notification.NotificationType.Info:
|
||||
return root.colorScheme.signal_info
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
color: colorScheme.background_norm
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
anchors.topMargin: 8
|
||||
anchors.bottomMargin: 8
|
||||
anchors.leftMargin: 24
|
||||
anchors.rightMargin: 24
|
||||
|
||||
spacing: 8
|
||||
|
||||
Status {
|
||||
id: statusItem
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
Layout.topMargin: 12
|
||||
Layout.bottomMargin: 12
|
||||
|
||||
colorScheme: root.colorScheme
|
||||
backend: root.backend
|
||||
notifications: root.notifications
|
||||
|
||||
notificationWhitelist: Notifications.Group.Connection | Notifications.Group.Update | Notifications.Group.Configuration
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
secondary: true
|
||||
|
||||
Layout.topMargin: 12
|
||||
Layout.bottomMargin: 12
|
||||
|
||||
visible: statusItem.activeNotification && statusItem.activeNotification.action.length > 0
|
||||
action: statusItem.activeNotification && statusItem.activeNotification.action.length > 0 ? statusItem.activeNotification.action[0] : null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: root.colorScheme.background_norm
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 24
|
||||
anchors.rightMargin: 24
|
||||
color: root.colorScheme.border_norm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Layout.maximumHeight: accountListView.count ?
|
||||
accountListView.contentHeight / accountListView.count * 3 + accountListView.anchors.topMargin + accountListView.anchors.bottomMargin :
|
||||
Number.POSITIVE_INFINITY
|
||||
|
||||
color: root.colorScheme.background_norm
|
||||
clip: true
|
||||
|
||||
implicitHeight: children[0].contentHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].contentWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
ListView {
|
||||
id: accountListView
|
||||
|
||||
model: root.backend.users
|
||||
anchors.fill: parent
|
||||
|
||||
anchors.topMargin: 8
|
||||
anchors.bottomMargin: 8
|
||||
anchors.leftMargin: 24
|
||||
anchors.rightMargin: 24
|
||||
|
||||
interactive: contentHeight > parent.height
|
||||
snapMode: ListView.SnapToItem
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
spacing: 4
|
||||
|
||||
delegate: Item {
|
||||
id: viewItem
|
||||
width: ListView.view.width
|
||||
|
||||
implicitHeight: children[0].implicitHeight
|
||||
implicitWidth: children[0].implicitWidth
|
||||
|
||||
property var user: root.backend.users.get(index)
|
||||
|
||||
RowLayout {
|
||||
spacing: 0
|
||||
anchors.fill: parent
|
||||
|
||||
AccountDelegate {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Layout.topMargin: 12
|
||||
Layout.bottomMargin: 12
|
||||
|
||||
user: viewItem.user
|
||||
colorScheme: root.colorScheme
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.topMargin: 12
|
||||
Layout.bottomMargin: 12
|
||||
|
||||
colorScheme: root.colorScheme
|
||||
visible: viewItem.user ? !viewItem.user.loggedIn : false
|
||||
text: qsTr("Sign in")
|
||||
onClicked: {
|
||||
root.showSignIn(viewItem.username)
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
|
||||
implicitHeight: children[1].implicitHeight + children[1].anchors.topMargin + children[1].anchors.bottomMargin
|
||||
implicitWidth: children[1].implicitWidth + children[1].anchors.leftMargin + children[1].anchors.rightMargin
|
||||
|
||||
// background:
|
||||
clip: true
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: parent.height * 2
|
||||
radius: ProtonStyle.dialog_radius
|
||||
|
||||
color: root.colorScheme.background_weak
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 8
|
||||
spacing: 0
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
secondary: true
|
||||
text: qsTr("Open Bridge")
|
||||
|
||||
borderless: true
|
||||
labelType: Label.LabelType.Caption_semibold
|
||||
|
||||
onClicked: {
|
||||
root.showMainWindow()
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
secondary: true
|
||||
icon.source: "./icons/ic-three-dots-vertical.svg"
|
||||
borderless: true
|
||||
checkable: true
|
||||
|
||||
onClicked: {
|
||||
menu.open()
|
||||
}
|
||||
|
||||
Menu {
|
||||
id: menu
|
||||
colorScheme: root.colorScheme
|
||||
modal: true
|
||||
|
||||
y: 0 - height
|
||||
|
||||
MenuItem {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Help")
|
||||
onClicked: {
|
||||
root.showHelp()
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Settings")
|
||||
onClicked: {
|
||||
root.showSettings()
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
MenuItem {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Quit Bridge")
|
||||
onClicked: {
|
||||
root.quit()
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
parent.checked = false
|
||||
}
|
||||
onOpened: {
|
||||
parent.checked = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
if (!active) root.close()
|
||||
}
|
||||
|
||||
function showAndRise() {
|
||||
root.show()
|
||||
root.raise()
|
||||
if (!root.active) {
|
||||
root.requestActivate()
|
||||
}
|
||||
}
|
||||
}
|
||||
278
internal/frontend/qt6/qml/WelcomeGuide.qml
Normal file
@ -0,0 +1,278 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick 2.13
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
import Proton 4.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property ColorScheme colorScheme
|
||||
|
||||
property var backend
|
||||
|
||||
implicitHeight: children[0].implicitHeight
|
||||
implicitWidth: children[0].implicitWidth
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
color: root.colorScheme.background_norm
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
implicitHeight: children[0].implicitHeight
|
||||
implicitWidth: children[0].implicitWidth
|
||||
|
||||
visible: signInItem.currentIndex == 0
|
||||
|
||||
GridLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
columnSpacing: 0
|
||||
rowSpacing: 0
|
||||
|
||||
columns: 3
|
||||
|
||||
// top margin
|
||||
Item {
|
||||
Layout.columnSpan: 3
|
||||
Layout.fillWidth: true
|
||||
|
||||
// Using binding component here instead of direct binding to avoid binding loop during construction of element
|
||||
Binding on Layout.preferredHeight {
|
||||
value: (parent.height - welcomeContentItem.height) / 4
|
||||
}
|
||||
}
|
||||
|
||||
// left margin
|
||||
Item {
|
||||
Layout.minimumWidth: 48
|
||||
Layout.maximumWidth: 80
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: welcomeContentItem.height
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: welcomeContentItem
|
||||
Layout.fillWidth: true
|
||||
spacing: 0
|
||||
|
||||
Image {
|
||||
source: colorScheme.welcome_img
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 16
|
||||
sourceSize.height: 148
|
||||
sourceSize.width: 264
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
text: qsTr("Welcome to\nProton Mail Bridge")
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
type: Label.LabelType.Heading
|
||||
}
|
||||
|
||||
Label {
|
||||
colorScheme: root.colorScheme
|
||||
id: longTextLabel
|
||||
text: qsTr("Add your Proton Mail account to securely access and manage your messages in your favorite email client. Bridge runs in the background and encrypts and decrypts your messages seamlessly.")
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 16
|
||||
Layout.preferredWidth: 320
|
||||
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
type: Label.LabelType.Body
|
||||
}
|
||||
}
|
||||
|
||||
// Right margin
|
||||
Item {
|
||||
Layout.minimumWidth: 48
|
||||
Layout.maximumWidth: 80
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: welcomeContentItem.height
|
||||
}
|
||||
|
||||
// bottom margin
|
||||
Item {
|
||||
Layout.columnSpan: 3
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.bottomMargin + children[0].anchors.topMargin
|
||||
implicitWidth: children[0].implicitWidth
|
||||
|
||||
Image {
|
||||
id: logoImage
|
||||
source: colorScheme.logo_img
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.topMargin: 48
|
||||
anchors.bottomMargin: 48
|
||||
sourceSize.height: 25
|
||||
sourceSize.width: 200
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: (signInItem.currentIndex == 0) ? root.colorScheme.background_weak : root.colorScheme.background_norm
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
implicitHeight: children[0].implicitHeight
|
||||
implicitWidth: children[0].implicitWidth
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: signInItem.currentIndex == 0 ? 0 : parent.width / 4
|
||||
|
||||
implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin
|
||||
implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin
|
||||
|
||||
Button {
|
||||
colorScheme: root.colorScheme
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
anchors.leftMargin: 80
|
||||
anchors.rightMargin: 80
|
||||
anchors.topMargin: 80
|
||||
anchors.bottomMargin: 80
|
||||
|
||||
visible: signInItem.currentIndex != 0
|
||||
|
||||
secondary: true
|
||||
text: qsTr("Back")
|
||||
|
||||
onClicked: {
|
||||
signInItem.abort()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
columnSpacing: 0
|
||||
rowSpacing: 0
|
||||
|
||||
columns: 3
|
||||
|
||||
// top margin
|
||||
Item {
|
||||
Layout.columnSpan: 3
|
||||
Layout.fillWidth: true
|
||||
|
||||
// Using binding component here instead of direct binding to avoid binding loop during construction of element
|
||||
Binding on Layout.preferredHeight {
|
||||
value: (parent.height - signInItem.height) / 4
|
||||
}
|
||||
}
|
||||
|
||||
// left margin
|
||||
Item {
|
||||
Layout.minimumWidth: 48
|
||||
Layout.maximumWidth: 80
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: signInItem.height
|
||||
}
|
||||
|
||||
|
||||
SignIn {
|
||||
id: signInItem
|
||||
colorScheme: root.colorScheme
|
||||
|
||||
Layout.preferredWidth: 320
|
||||
Layout.fillWidth: true
|
||||
|
||||
username: root.backend.users.count === 1 && root.backend.users.get(0) && root.backend.users.get(0).loggedIn === false ? root.backend.users.get(0).username : ""
|
||||
backend: root.backend
|
||||
}
|
||||
|
||||
// Right margin
|
||||
Item {
|
||||
Layout.minimumWidth: 48
|
||||
Layout.maximumWidth: 80
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: signInItem.height
|
||||
}
|
||||
|
||||
// bottom margin
|
||||
Item {
|
||||
Layout.columnSpan: 3
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: signInItem.currentIndex == 0 ? 0 : parent.width / 4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "Page 1"
|
||||
PropertyChanges {
|
||||
target: signInItem
|
||||
currentIndex: 0
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "Page 2"
|
||||
PropertyChanges {
|
||||
target: signInItem
|
||||
currentIndex: 1
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "Page 3"
|
||||
PropertyChanges {
|
||||
target: signInItem
|
||||
currentIndex: 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
37
internal/frontend/qt6/qml/bridgeqml.qmlproject
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2022 Proton AG
|
||||
//
|
||||
// This file is part of Proton Mail Bridge.
|
||||
//
|
||||
// Proton Mail 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.
|
||||
//
|
||||
// Proton Mail 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 Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import QmlProject 1.1
|
||||
|
||||
Project {
|
||||
mainFile: "./MainWindow.qml"
|
||||
|
||||
/* Include .qml, .js, and image files from current directory and subdirectories */
|
||||
QmlFiles {
|
||||
directory: "./"
|
||||
}
|
||||
JavaScriptFiles {
|
||||
directory: "./"
|
||||
}
|
||||
ImageFiles {
|
||||
directory: "./"
|
||||
}
|
||||
/* List of plugin directories passed to QML runtime */
|
||||
importPaths: [
|
||||
"./"
|
||||
]
|
||||
}
|
||||
4
internal/frontend/qt6/qml/icons/Loader_16.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.2" d="M8 2.75C8.68944 2.75 9.37213 2.8858 10.0091 3.14963C10.646 3.41347 11.2248 3.80018 11.7123 4.28769C12.1998 4.7752 12.5865 5.35395 12.8504 5.99091C13.1142 6.62787 13.25 7.31056 13.25 8C13.25 8.68944 13.1142 9.37213 12.8504 10.0091C12.5865 10.646 12.1998 11.2248 11.7123 11.7123C11.2248 12.1998 10.646 12.5865 10.0091 12.8504C9.37213 13.1142 8.68944 13.25 8 13.25C7.31056 13.25 6.62787 13.1142 5.99091 12.8504C5.35395 12.5865 4.7752 12.1998 4.28769 11.7123C3.80018 11.2248 3.41347 10.646 3.14963 10.0091C2.88579 9.37213 2.75 8.68944 2.75 8C2.75 7.31056 2.8858 6.62787 3.14963 5.99091C3.41347 5.35395 3.80018 4.77519 4.28769 4.28769C4.7752 3.80018 5.35396 3.41347 5.99092 3.14963C6.62787 2.88579 7.31056 2.75 8 2.75L8 2.75Z" stroke="#5064B6" stroke-width="1.5"/>
|
||||
<path d="M11.7123 11.7123C11.1018 12.3228 10.3502 12.7733 9.52399 13.0239C8.6978 13.2746 7.82255 13.3176 6.97578 13.1491C6.129 12.9807 5.33683 12.606 4.66944 12.0583C4.00204 11.5106 3.48003 10.8067 3.14963 10.0091C2.81924 9.21144 2.69066 8.34462 2.77528 7.48541C2.85991 6.6262 3.15512 5.80112 3.63478 5.08326C4.11445 4.36539 4.76374 3.7769 5.52517 3.36991C6.28659 2.96292 7.13663 2.75 8 2.75" stroke="#5064B6" stroke-width="1.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
4
internal/frontend/qt6/qml/icons/Loader_48.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.2" d="M24 1C27.0204 1 30.0112 1.59491 32.8017 2.75077C35.5922 3.90663 38.1277 5.6008 40.2635 7.73655C42.3992 9.87229 44.0934 12.4078 45.2492 15.1983C46.4051 17.9888 47 20.9796 47 24C47 27.0204 46.4051 30.0112 45.2492 32.8017C44.0934 35.5922 42.3992 38.1277 40.2635 40.2635C38.1277 42.3992 35.5922 44.0934 32.8017 45.2492C30.0112 46.4051 27.0204 47 24 47C20.9796 47 17.9888 46.4051 15.1983 45.2492C12.4078 44.0934 9.87228 42.3992 7.73654 40.2634C5.60079 38.1277 3.90662 35.5922 2.75077 32.8017C1.59491 30.0112 0.999998 27.0204 1 24C1 20.9796 1.59492 17.9888 2.75078 15.1983C3.90664 12.4078 5.6008 9.87228 7.73655 7.73653C9.8723 5.60079 12.4078 3.90662 15.1983 2.75077C17.9888 1.59491 20.9796 0.999998 24 1L24 1Z" stroke="#5064B6" stroke-width="2"/>
|
||||
<path d="M40.2635 40.2635C37.5889 42.938 34.2961 44.9117 30.6765 46.0096C27.057 47.1076 23.2226 47.296 19.5129 46.5581C15.8032 45.8202 12.3328 44.1788 9.40895 41.7792C6.48514 39.3797 4.19822 36.2962 2.75077 32.8017C1.30332 29.3073 0.740014 25.5098 1.11075 21.7456C1.48149 17.9814 2.77483 14.3668 4.8762 11.2219C6.97757 8.07696 9.82212 5.49881 13.1579 3.71581C16.4936 1.93281 20.2176 1 24 1" stroke="#5064B6" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
11
internal/frontend/qt6/qml/icons/ic-alert.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M25.9729 8.06214C28.6889 3.51461 35.2762 3.51461 37.9923 8.06214L62.464 49.0356C65.2508 53.7015 61.8891 59.625 56.4543 59.625H7.51078C2.07602 59.625 -1.28569 53.7015 1.50106 49.0356L25.9729 8.06214Z" fill="url(#paint0_linear)"/>
|
||||
<path d="M29.0775 24.3888C29.0864 22.7908 30.3843 21.5 31.9824 21.5C33.5805 21.5 34.8785 22.7908 34.8874 24.3888L34.9658 38.5C34.9749 40.1542 33.6366 41.5 31.9824 41.5C30.3283 41.5 28.9899 40.1542 28.9991 38.5L29.0775 24.3888Z" fill="white"/>
|
||||
<path d="M34.9824 47.5C34.9824 49.1569 33.6393 50.5 31.9824 50.5C30.3256 50.5 28.9824 49.1569 28.9824 47.5C28.9824 45.8431 30.3256 44.5 31.9824 44.5C33.6393 44.5 34.9824 45.8431 34.9824 47.5Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="31.9827" y1="4.18421" x2="31.9827" y2="84.2072" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FF7171"/>
|
||||
<stop offset="1" stop-color="#E63757"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1013 B |
10
internal/frontend/qt6/qml/icons/ic-apple-mail.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.29416 0.0598755H27.7073C32.2688 0.0598755 35.9409 3.73205 35.9409 8.29347V27.7067C35.9409 32.2681 32.2688 35.9403 27.7073 35.9403H8.29416C3.73273 35.9403 0.0605469 32.2681 0.0605469 27.7067V8.29347C0.0605469 3.73205 3.73273 0.0598755 8.29416 0.0598755Z" fill="url(#paint0_linear)"/>
|
||||
<path d="M7.92234 10.2633C7.73329 10.2633 7.55519 10.2959 7.38662 10.363L10.7629 13.8389L14.1765 17.3771L14.2388 17.4518L14.3385 17.5515L14.4381 17.6512L14.6375 17.863L17.5652 20.8655C17.6139 20.8958 17.7552 21.0266 17.8656 21.0818C18.0077 21.1529 18.1618 21.2183 18.3207 21.224C18.492 21.2302 18.6672 21.1811 18.8215 21.106C18.937 21.0498 18.9883 20.9693 19.1225 20.8655L22.5112 17.3646L25.9373 13.8389L29.2388 10.4377C29.0268 10.3229 28.7921 10.2633 28.5411 10.2633H7.92234ZM6.88828 10.6869C6.52824 11.028 6.30273 11.5409 6.30273 12.1196V23.5316C6.30273 24.0002 6.45323 24.4258 6.70141 24.7525L7.17483 24.304L10.7006 20.8779L13.8277 17.8505L13.7654 17.7758L10.3393 14.25L6.9132 10.7118L6.88828 10.6869ZM29.6873 10.799L26.3484 14.25L22.9348 17.7758L22.8725 17.8381L26.1242 20.9901L29.6499 24.4161L29.8617 24.6155C30.0516 24.3109 30.1607 23.9357 30.1607 23.5316V12.1196C30.1607 11.6036 29.9819 11.1357 29.6873 10.799ZM14.2263 18.2617L11.1117 21.2891L7.5735 24.7151L7.12499 25.1512C7.36144 25.3035 7.63053 25.4004 7.92234 25.4004H28.5411C28.8919 25.4004 29.2101 25.2654 29.4755 25.0515L29.2513 24.8273L25.713 21.4012L22.4614 18.2617L19.5336 21.2766C19.3752 21.3817 19.2693 21.4982 19.1146 21.5697C18.8656 21.6849 18.5926 21.7823 18.3183 21.7781C18.0433 21.7739 17.7736 21.6662 17.5267 21.5448C17.4028 21.4839 17.3368 21.4233 17.1914 21.3015L14.2263 18.2617Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="18.252" y1="35.7962" x2="18.2869" y2="0.493036" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#70EFFF"/>
|
||||
<stop offset="1" stop-color="#5770FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
5
internal/frontend/qt6/qml/icons/ic-arrow-left.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="ic-arrow-left">
|
||||
<path id="icon" fill-rule="evenodd" clip-rule="evenodd" d="M14 8H3.20998L7.68998 3.52L6.97998 2.81L1.28998 8.5L6.97998 14.19L7.68998 13.48L3.20998 9H14V8Z" fill="#17181C"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 304 B |
62
internal/frontend/qt6/qml/icons/ic-card-identity.svg
Normal file
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg12"
|
||||
sodipodi:docname="ic-card-identity.svg"
|
||||
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs16" />
|
||||
<sodipodi:namedview
|
||||
id="namedview14"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:pageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="40.25"
|
||||
inkscape:cx="7.9875776"
|
||||
inkscape:cy="8"
|
||||
inkscape:window-width="2556"
|
||||
inkscape:window-height="1401"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="18"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg12" />
|
||||
<g
|
||||
id="ic-card-identity"
|
||||
transform="translate(0,-3.9095641)">
|
||||
<g
|
||||
id="icon">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M 5.32,9.64 C 5.96894,9.64404 6.55605,9.25571 6.80626,8.65693 7.05647,8.05815 6.92022,7.36754 6.46134,6.90866 6.00246,6.44978 5.31185,6.31353 4.71307,6.56374 4.11429,6.81395 3.72596,7.40106 3.73,8.05 c 0,0.87813 0.71187,1.59 1.59,1.59 z m 0,-2.19 C 5.61898,7.48884 5.8427,7.74351 5.8427,8.045 5.8427,8.34649 5.61898,8.60116 5.32,8.64 5.02102,8.60116 4.7973,8.34649 4.7973,8.045 4.7973,7.74351 5.02102,7.48884 5.32,7.45 Z"
|
||||
fill="#0c0c14"
|
||||
id="path2" />
|
||||
<path
|
||||
d="m 9,8 h 4 V 9 H 9 Z"
|
||||
fill="#0c0c14"
|
||||
id="path4" />
|
||||
<path
|
||||
d="M 13,10 H 9 v 1 h 4 z"
|
||||
fill="#0c0c14"
|
||||
id="path6" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M 1,14 V 4 H 15 V 14 Z M 3.64,12.49 V 13 H 7 V 12.49 L 6.1,11.57 H 4.54 Z M 14,13 H 8 V 12.08 L 6.52,10.57 H 4.12 L 2.64,12.08 V 13 H 2 V 5 h 12 z"
|
||||
fill="#0c0c14"
|
||||
id="path8" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
3
internal/frontend/qt6/qml/icons/ic-check.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 8.5L2.7 7.8L6.05 11.14L13.2 4L13.9 4.7L6.05 12.56L2 8.5Z" fill="#17181C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 230 B |
5
internal/frontend/qt6/qml/icons/ic-chevron-down.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="ic-chevron-down">
|
||||
<path id="icon" fill-rule="evenodd" clip-rule="evenodd" d="M2.3 6.30001L8 12L13.7 6.30001L13 5.60001L8 10.58L3 5.60001L2.3 6.30001Z" fill="#17181C"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 283 B |
5
internal/frontend/qt6/qml/icons/ic-chevron-up.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="ic-chevron-up">
|
||||
<path id="icon" fill-rule="evenodd" clip-rule="evenodd" d="M13.7 9.7L7.99999 4L2.29999 9.7L2.99999 10.4L7.99999 5.42L13 10.4L13.7 9.7Z" fill="#17181C"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 284 B |
3
internal/frontend/qt6/qml/icons/ic-cog-wheel.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.7166 1H9.29278L9.83484 2.72079C10.0427 2.79404 10.2448 2.87886 10.4428 2.97503L12.04 2.14318L13.8662 3.97057L13.035 5.56869C13.1312 5.7671 13.2161 5.96972 13.2894 6.178L15 6.72052V9.29956L13.2799 9.83276C13.2068 10.0403 13.1222 10.2423 13.0262 10.4401L13.8574 12.0382L12.0312 13.8656L10.434 13.0338C10.2359 13.13 10.0336 13.2149 9.82558 13.2882L9.2834 15H6.70782L6.16564 13.2882C5.95765 13.2149 5.75532 13.13 5.55718 13.0338L3.95998 13.8656L2.13382 12.0382L2.96503 10.4401C2.86877 10.2417 2.78388 10.0391 2.71059 9.83078L1 9.28826V6.71174L2.71059 6.16922C2.78388 5.96094 2.86877 5.75832 2.96503 5.55991L2.13323 3.96064L3.96989 2.13499L5.56596 2.96625C5.76409 2.87 5.96643 2.78513 6.17441 2.71184L6.7166 1ZM7.44883 2L6.97047 3.51034L6.71736 3.58632C6.40057 3.68142 6.09845 3.8085 5.80203 3.96884L5.56858 4.09511L4.15637 3.35961L3.35968 4.15152L4.09358 5.56254L3.9676 5.79574C3.80736 6.0924 3.68034 6.39477 3.58529 6.71183L3.5094 6.96496L2 7.44367V8.55633L3.5094 9.03504L3.58529 9.28817C3.68034 9.60523 3.80736 9.9076 3.9676 10.2043L4.09358 10.4375L3.35909 11.8496L4.14873 12.6398L5.5598 11.9049L5.79325 12.0312C6.08967 12.1915 6.39179 12.3186 6.70858 12.4137L6.96169 12.4897L7.44005 14H8.55117L9.02953 12.4897L9.28264 12.4137C9.59943 12.3186 9.90155 12.1915 10.198 12.0312L10.4314 11.9049L11.8425 12.6398L12.6321 11.8496L11.8976 10.4375L12.0236 10.2043C12.1839 9.9076 12.3109 9.60523 12.4059 9.28817L12.4824 9.03304L14 8.5626V7.45245L12.4906 6.97374L12.4147 6.72061C12.3197 6.40355 12.1926 6.10118 12.0324 5.80453L11.9064 5.57132L12.6409 4.15916L11.8513 3.36898L10.4402 4.1039L10.2067 3.97762C9.91033 3.81729 9.60821 3.6902 9.29142 3.5951L9.03783 3.51898L8.55935 2H7.44883ZM7.99561 5.81216C6.78861 5.81216 5.80959 6.79136 5.80959 8C5.80959 9.20864 6.78861 10.1878 7.99561 10.1878C9.20261 10.1878 10.1816 9.20864 10.1816 8C10.1816 6.79136 9.20261 5.81216 7.99561 5.81216ZM4.80959 8C4.80959 6.23972 6.23569 4.81216 7.99561 4.81216C9.75553 4.81216 11.1816 6.23972 11.1816 8C11.1816 9.76028 9.75553 11.1878 7.99561 11.1878C6.23569 11.1878 4.80959 9.76028 4.80959 8Z" fill="#17181C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
5
internal/frontend/qt6/qml/icons/ic-connected.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.9257 5.48656C13.8921 3.271 11.0022 2 8 2C4.99776 2 2.10791 3.271 0.0743047 5.48656C-0.0273754 5.59626 -0.0246996 5.76751 0.0823321 5.87455L1.67175 7.4637C1.78146 7.57341 1.95806 7.57341 2.06777 7.4637C2.0865 7.44524 2.09988 7.42383 2.11058 7.39975C3.61705 5.74584 5.76036 4.7962 8 4.7962C10.2396 4.7962 12.3829 5.74611 13.8894 7.39975C13.9001 7.42383 13.9135 7.44524 13.9322 7.4637C13.9857 7.51989 14.058 7.54692 14.1302 7.54692C14.2025 7.54692 14.2747 7.51989 14.3282 7.4637L15.9177 5.87455C16.0247 5.76751 16.0274 5.59653 15.9257 5.48656Z" fill="#349172"/>
|
||||
<path d="M12.7547 8.56633C11.5533 7.20168 9.82473 6.41794 7.99984 6.41794C6.17495 6.41794 4.44639 7.20195 3.24228 8.56633C3.2289 8.57436 3.21285 8.58265 3.19947 8.59577C3.08976 8.70547 3.08976 8.88208 3.19947 8.99151L4.72735 10.5194C4.7541 10.5488 4.78621 10.5678 4.821 10.5809C4.83705 10.589 4.85311 10.589 4.86649 10.5916C4.88789 10.5943 4.90662 10.6023 4.92535 10.6023C4.92803 10.6023 4.93071 10.5997 4.93338 10.5997C4.93606 10.5997 4.93873 10.6023 4.94141 10.6023C4.95211 10.6023 4.96281 10.5943 4.97352 10.5916C4.9976 10.589 5.02168 10.5836 5.04309 10.5729C5.05914 10.5676 5.06985 10.5569 5.08323 10.5462C5.0966 10.5381 5.11266 10.5328 5.12336 10.5191C5.12871 10.5164 5.12871 10.5087 5.13407 10.5057C5.13674 10.5004 5.14209 10.5004 5.14477 10.495C5.83512 9.62006 6.87601 9.11969 7.99984 9.11969C9.12367 9.11969 10.1646 9.62006 10.8549 10.495C10.8576 10.5007 10.8629 10.5007 10.8656 10.5057C10.871 10.5114 10.871 10.5164 10.8763 10.5191C10.887 10.5328 10.9031 10.5379 10.9165 10.5462C10.9298 10.5569 10.9405 10.5676 10.9566 10.5729C10.978 10.5836 11.0021 10.5892 11.0262 10.5916C11.0369 10.5943 11.0476 10.6023 11.0583 10.6023H11.0743C11.1118 10.6023 11.1466 10.5943 11.1814 10.5809C11.2161 10.5676 11.2456 10.5461 11.2723 10.5194L12.8002 8.99151C12.9099 8.88208 12.9099 8.70547 12.8002 8.59577C12.7868 8.58265 12.7708 8.57436 12.7547 8.56633Z" fill="#349172"/>
|
||||
<path d="M7.99991 10.2626C7.17309 10.2626 6.50146 10.9371 6.50146 11.7637C6.50146 12.5902 7.17309 13.2621 7.99991 13.2621C8.82673 13.2621 9.49835 12.5905 9.49835 11.7637C9.49835 10.9369 8.82673 10.2626 7.99991 10.2626Z" fill="#349172"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
4
internal/frontend/qt6/qml/icons/ic-copy.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="12" height="13" viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 2V0H12V10H9V9H11V1H5V2H4Z" fill="#262A33"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 3V13H8V3H0ZM7 4V12H1V4H7Z" fill="#262A33"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 255 B |
3
internal/frontend/qt6/qml/icons/ic-cross-close.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.85 2.8499L13.15 2.1499L8 7.2899L2.85 2.1499L2.15 2.8499L7.29 7.9999L2.15 13.1499L2.85 13.8499L8 8.7099L13.15 13.8499L13.85 13.1499L8.71 7.9999L13.85 2.8499Z" fill="#17181C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 331 B |
3
internal/frontend/qt6/qml/icons/ic-drive.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.8561 3.06675L13.9015 7.66688H2.09846L4.14391 3.06675H11.8561ZM14 8.68913H2V12.267H14V8.68913ZM12.5 2.04449H3.5L1 7.66688V13.2893H15V7.66688L12.5 2.04449ZM12 10.9381V9.91584H13V10.9381H12ZM10 10.9381H11V9.91584H10V10.9381Z" fill="#0C0C14"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 396 B |
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15ZM7.5 5V9H8.5V5H7.5ZM7.5 10V11H8.5V10H7.5Z" fill="#17181C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 316 B |
3
internal/frontend/qt6/qml/icons/ic-external-link.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 2L13.2427 2L13.2427 1.99998L13.2426 2L13 2L9 2V3H12.2426L5.76613 9.47651L6.47324 10.1836L13 3.65686V7H14V3V2ZM2 2H5V3H3L3 13L13 13V11H14V14H13H3H2V13V3V2Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 327 B |
9
internal/frontend/qt6/qml/icons/ic-eye-slash.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="ic-eye-slash">
|
||||
<g id="icon">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11 4.33002L13.15 2.15002L13.86 2.84002L2.85999 13.84L2.15999 13.14L4.15999 11.14C3.12487 10.3566 2.24914 9.38244 1.57999 8.27002L1.39999 8.00002L1.57999 7.70002C3.14999 5.31002 4.83999 3.70002 7.99999 3.70002C9.03578 3.66939 10.064 3.88532 11 4.33002ZM6.92814 6.91817C6.47409 7.37223 6.362 8.0661 6.64999 8.64003L8.64999 6.64003C8.07607 6.35203 7.3822 6.46412 6.92814 6.91817ZM9.36999 5.93002C8.96735 5.65139 8.48965 5.50146 7.99999 5.50002C6.61928 5.50002 5.49999 6.61931 5.49999 8.00002C5.50143 8.48968 5.65136 8.96738 5.92999 9.37002L4.86999 10.42C3.96048 9.77171 3.18887 8.94911 2.59999 8.00002C3.99999 6.00002 5.39999 4.70002 7.99999 4.70002C8.75151 4.68822 9.49833 4.82061 10.2 5.09002L9.36999 5.93002Z" fill="#17181C"/>
|
||||
<path d="M14.42 7.73002C13.8714 6.82671 13.1981 6.00529 12.42 5.29002L11.7 6.00002C12.3591 6.5822 12.9316 7.25569 13.4 8.00002C12 10 10.6 11.3 7.99999 11.3C7.51257 11.3044 7.0262 11.2541 6.54999 11.15L5.73999 12C6.47229 12.2209 7.23543 12.3222 7.99999 12.3C11.16 12.3 12.85 10.69 14.42 8.30002L14.6 8.00002L14.42 7.73002Z" fill="#17181C"/>
|
||||
<path d="M8.21999 9.48002L7.29999 10.4C7.52685 10.4689 7.76292 10.5027 7.99999 10.5C8.66304 10.5 9.29892 10.2366 9.76776 9.76779C10.2366 9.29895 10.5 8.66307 10.5 8.00002C10.5026 7.76295 10.4689 7.52688 10.4 7.30002L9.47999 8.22003C9.38822 8.87414 8.8741 9.38825 8.21999 9.48002Z" fill="#17181C"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
8
internal/frontend/qt6/qml/icons/ic-eye.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="ic-eye">
|
||||
<g id="icon">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.99999 5.49998C6.61928 5.49998 5.49999 6.61927 5.49999 7.99998C5.49999 9.38069 6.61928 10.5 7.99999 10.5C9.38071 10.5 10.5 9.38069 10.5 7.99998C10.5 7.33694 10.2366 6.70106 9.76776 6.23221C9.29892 5.76337 8.66304 5.49998 7.99999 5.49998ZM7.99999 9.49998C7.17157 9.49998 6.49999 8.82841 6.49999 7.99998C6.49999 7.17155 7.17157 6.49998 7.99999 6.49998C8.82842 6.49998 9.49999 7.17155 9.49999 7.99998C9.49999 8.82841 8.82842 9.49998 7.99999 9.49998Z" fill="#17181C"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.42 7.72998C12.85 5.30998 11.16 3.72998 7.99999 3.72998C4.83999 3.72998 3.14999 5.33998 1.57999 7.72998L1.39999 7.99998L1.57999 8.26998C3.14999 10.69 4.83999 12.27 7.99999 12.27C11.16 12.27 12.85 10.66 14.42 8.26998L14.6 7.99998L14.42 7.72998ZM7.99999 11.3C5.39999 11.3 3.99999 9.99998 2.59999 7.99998C3.99999 5.99998 5.39999 4.69998 7.99999 4.69998C10.6 4.69998 12 5.99998 13.4 7.99998C12 9.99998 10.6 11.3 7.99999 11.3Z" fill="#17181C"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1,8 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="ic-illustrative-view-html-code">
|
||||
<g id="icon">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.8 9.83C5.017 9.94015 5.25665 9.99835 5.5 10C5.66952 10.0069 5.8389 9.98323 6 9.93C6.67538 9.71289 7.10403 9.04971 7.02464 8.34474C6.94525 7.63978 6.37983 7.08855 5.67308 7.02709C4.96633 6.96564 4.31425 7.411 4.11437 8.09168C3.91448 8.77236 4.22223 9.49957 4.85 9.83H4.8ZM5.06 8.27C5.11328 8.14244 5.21896 8.04404 5.35 8H5.5C5.5806 7.9995 5.65991 8.0202 5.73 8.06C5.85756 8.11328 5.95596 8.21896 6 8.35C6.05001 8.47173 6.05001 8.60827 6 8.73C5.93418 8.87156 5.80363 8.97227 5.65 9C5.52827 9.05001 5.39173 9.05001 5.27 9C5.12844 8.93418 5.02773 8.80363 5 8.65C4.96852 8.5204 4.99012 8.3836 5.06 8.27Z" fill="#0C0C14"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 2V15H15V2H1ZM14 14H2V12.79L4.2 11.49L6.56 12L10.45 10.05L14 12.75V14ZM10.55 8.92L14 11.5V6H2V11.63L4 10.43L6.44 11L10.55 8.92ZM14 5H2V3H10V4H11V3H12V4H13V3H14V5Z" fill="#0C0C14"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15C11.866 15 15 11.866 15 8C15 6.14348 14.2625 4.36301 12.9497 3.05025C11.637 1.7375 9.85652 1 8 1ZM8.5 4V5H7.5V4H8.5ZM8.5 6V11H9.5V12H6.5V11H7.5V7H6.5V6H8.5Z" fill="#17181C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 380 B |
12
internal/frontend/qt6/qml/icons/ic-info.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="32" cy="32" r="30" fill="url(#paint0_linear)"/>
|
||||
<path d="M32 18C30.3431 18 29 19.3431 29 21C29 22.6569 30.3431 24 32 24C33.6569 24 35 22.6569 35 21C35 19.3431 33.6569 18 32 18Z" fill="white"/>
|
||||
<path d="M30 28C28.8954 28 28 28.8954 28 30C28 31.1046 28.8954 32 30 32V42C28.8954 42 28 42.8954 28 44C28 45.1046 28.8954 46 30 46H34C35.1046 46 36 45.1046 36 44C36 42.8954 35.1046 42 34 42V30C34 28.8954 33.1046 28 32 28H30Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="32" y1="62" x2="14.4192" y2="7.69125" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#4F6DE6"/>
|
||||
<stop offset="0.483234" stop-color="#63A1FE"/>
|
||||
<stop offset="1" stop-color="#82D2FF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 807 B |
20
internal/frontend/qt6/qml/icons/ic-microsoft-outlook.svg
Normal file
@ -0,0 +1,20 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M32.1672 2.25H12.8275C11.961 2.25 11.248 2.96301 11.248 3.82952V5.62489L22.1485 9.0001L33.7466 5.62489V3.82952C33.7466 2.96301 33.0336 2.25 32.1672 2.25Z" fill="#0364B8"/>
|
||||
<path d="M35.6033 19.5809C35.7681 19.0629 35.8997 18.535 35.9971 18.0002C35.9972 17.7327 35.8542 17.4847 35.6225 17.351L35.6079 17.3432L35.6033 17.3411L23.4113 10.3952C23.3588 10.3612 23.3043 10.3299 23.2483 10.3018C22.7762 10.0678 22.2208 10.0678 21.7487 10.3018C21.6928 10.3299 21.6383 10.361 21.5856 10.3952L9.39371 17.3411L9.38913 17.3432L9.3744 17.351C9.14286 17.4847 8.99984 17.7327 9 18.0002C9.09736 18.535 9.22893 19.0629 9.39371 19.5809L22.3213 29.0364L35.6033 19.5809Z" fill="#0A2767"/>
|
||||
<path d="M26.9977 5.625H19.1232L16.8496 9.00021L19.1232 12.3751L26.9977 19.125H33.7472V12.3751L26.9977 5.625Z" fill="#28A8EA"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.25 5.625H19.1245V12.3749H11.25V5.625Z" fill="#0078D4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.998 5.625H33.7476V12.3749H26.998V5.625Z" fill="#50D9FF"/>
|
||||
<path d="M26.999 19.1251L19.1245 12.3752H11.25V19.1251L19.1245 25.8752L31.3097 27.8642L26.999 19.1251Z" fill="#0364B8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.123 12.3752H26.9976V19.1251H19.123V12.3752Z" fill="#0078D4"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.25 19.125H19.1245V25.8749H11.25V19.125Z" fill="#064A8C"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.998 19.125H33.7476V25.8749H26.998V19.125Z" fill="#0078D4"/>
|
||||
<path d="M22.7128 28.3704L9.44531 18.6955L10.001 17.7179C10.001 17.7179 22.0883 24.6028 22.2728 24.7064C22.4256 24.7678 22.5974 24.7628 22.7465 24.6928C22.9185 24.5961 35.0441 17.6841 35.0441 17.6841L35.6021 18.6618L22.7128 28.3704Z" fill="#0A2767" fill-opacity="0.498039"/>
|
||||
<path d="M35.6238 18.6492L35.6092 18.6582L35.6058 18.6605L23.4139 25.6063C22.922 25.9235 22.2989 25.9623 21.7715 25.7086L26.018 31.4022L35.3032 33.4239V33.4285C35.741 33.1118 36.0008 32.603 36.0006 32.0627V18.0002C36.0008 18.2676 35.8576 18.5157 35.6261 18.6492H35.6238Z" fill="#1490DF"/>
|
||||
<path d="M35.9976 32.0629V31.2328L24.7674 24.8337L23.4118 25.6054C22.9201 25.9226 22.2969 25.9615 21.7695 25.7077L26.0161 31.4015L35.3013 33.423V33.4276C35.739 33.1108 35.9987 32.6022 35.9987 32.0618L35.9976 32.0629Z" fill="black" fill-opacity="0.047059"/>
|
||||
<path d="M35.9414 32.4937L23.6312 25.4804L23.4118 25.6053C22.9201 25.9224 22.2969 25.9614 21.7695 25.7075L26.0161 31.4013L35.3013 33.4228V33.4274C35.6163 33.199 35.8429 32.8686 35.9424 32.4925L35.9414 32.4937Z" fill="black" fill-opacity="0.098039"/>
|
||||
<path d="M9.39373 18.6639V18.6526H9.38261L9.34873 18.6302C9.13044 18.4959 8.9979 18.2565 9.00003 18.0002V32.065C9.00003 32.9894 9.76077 33.7502 10.6853 33.7502H34.3111C34.4515 33.7487 34.5914 33.7299 34.7273 33.6939C34.7978 33.6816 34.866 33.6589 34.9298 33.6265C34.9537 33.624 34.9766 33.6163 34.9973 33.6039C35.0892 33.5663 35.1763 33.5172 35.256 33.4576L35.301 33.4239L9.39373 18.6639Z" fill="#28A8EA"/>
|
||||
<path d="M20.2493 27.7507V9.37612C20.2469 8.55429 19.5716 7.87892 18.7498 7.87646H11.2849V16.2643L9.39371 17.3421L9.38929 17.3444L9.37473 17.3523C9.14302 17.4861 9 17.7341 9 18.0013V29.2548V29.2502H18.7498C19.5716 29.2479 20.2469 28.5724 20.2493 27.7507Z" fill="black" fill-opacity="0.098039"/>
|
||||
<path d="M19.1245 28.8755V10.5009C19.1221 9.67927 18.4466 9.0039 17.6249 9.00128H11.2849V16.2643L9.39371 17.342L9.38929 17.3443L9.37473 17.3522C9.14302 17.486 9 17.734 9 18.0012V30.3798V30.3752H17.6249C18.4466 30.3727 19.1221 29.6974 19.1245 28.8755ZM19.1245 26.6255V10.5009C19.1221 9.67927 18.4466 9.0039 17.6249 9.00128H11.2849V16.2643L9.39371 17.342L9.38929 17.3443L9.37473 17.3522C9.14302 17.486 9 17.734 9 18.0012V28.1296V28.1252H17.6249C18.4466 28.1228 19.1221 27.4474 19.1245 26.6255ZM17.9995 26.6255V10.5009C17.9971 9.67927 17.3217 9.0039 16.5001 9.00128H11.2849V16.2643L9.39371 17.342L9.38929 17.3443L9.37473 17.3522C9.14302 17.486 9 17.734 9 18.0012V28.1296V28.1252H16.5001C17.3217 28.1228 17.9971 27.4474 17.9995 26.6255Z" fill="black" fill-opacity="0.2"/>
|
||||
<path d="M1.49956 9.00037H16.4981C17.3207 9.00037 17.9977 9.67721 17.9977 10.4999V25.4996C17.9977 26.3222 17.3207 26.9992 16.4981 26.9992H1.49956C0.676964 26.9992 0 26.3222 0 25.4996V10.4999C0 9.67721 0.676964 9.00037 1.49956 9.00037Z" fill="#0078D4"/>
|
||||
<path d="M4.35008 15.1517C4.74854 14.3026 5.39195 13.5919 6.19721 13.1111C7.08952 12.6002 8.10554 12.3457 9.13334 12.3753C10.0852 12.3544 11.0248 12.5957 11.8489 13.0728C12.6244 13.5346 13.249 14.2121 13.6464 15.0225C14.0794 15.9153 14.2954 16.8978 14.2764 17.89C14.2975 18.9271 14.0752 19.9548 13.6274 20.8905C13.2211 21.7295 12.5777 22.4314 11.7769 22.9088C10.9207 23.4008 9.94612 23.6488 8.9589 23.6254C7.98641 23.6484 7.02603 23.4044 6.18265 22.9199C5.40112 22.4573 4.76899 21.7791 4.36252 20.9669C3.92676 20.0868 3.7083 19.1149 3.72581 18.1331C3.7065 17.1049 3.92037 16.0857 4.35123 15.1517H4.35008ZM6.31863 19.942C6.53119 20.4789 6.89168 20.9448 7.35821 21.2852C7.83292 21.6177 8.40205 21.7892 8.98132 21.7747C9.59856 21.7991 10.2071 21.6222 10.7149 21.2707C11.1757 20.9303 11.5267 20.4619 11.724 19.924C11.9459 19.3244 12.0552 18.689 12.0469 18.0498C12.0538 17.405 11.951 16.7635 11.7432 16.1531C11.5599 15.6036 11.2215 15.1185 10.7689 14.757C10.2745 14.3878 9.66761 14.2003 9.05119 14.226C8.45932 14.2106 7.87743 14.3831 7.38963 14.7187C6.91443 15.0603 6.54592 15.5301 6.32763 16.0732C5.8449 17.3168 5.84212 18.6967 6.31977 19.942H6.31863Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
112
internal/frontend/qt6/qml/icons/ic-mozilla-thunderbird.svg
Normal file
@ -0,0 +1,112 @@
|
||||
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.429 5.15378C25.3233 3.77844 22.6304 3.33309 21.1443 3.17756C19.5536 3.0113 18.1721 3.04053 16.9571 3.2189C16.8541 3.21753 16.7518 3.21365 16.6484 3.21365C16.5693 3.21365 16.4915 3.21707 16.412 3.21799C16.4446 3.17802 16.4673 3.15335 16.4673 3.15335C16.4673 3.15335 16.4033 3.1634 16.2779 3.22027C15.8835 3.22666 15.4907 3.24037 15.104 3.26686C15.6428 2.67626 16.0843 2.36657 16.0843 2.36657C16.0843 2.36657 15.5603 2.4433 14.6043 3.3098C14.1496 3.35159 13.7008 3.40709 13.26 3.47606C14.2647 2.11671 15.3155 1.54415 15.3155 1.54415C15.3155 1.54415 14.0418 1.28494 12.0473 3.28901C11.8804 3.45688 11.7258 3.63113 11.5759 3.80768C5.76262 5.21407 1.60236 8.96803 1.60236 13.3795C1.60236 14.2446 1.33675 15.1961 1.62314 16.1464C1.50872 17.6642 1.75241 21.806 1.75241 21.806C1.75241 21.806 3.32598 30.3225 9.37727 31.8031C9.47342 31.8262 8.11293 29.6803 7.51114 27.0922C8.68275 28.2839 10.0791 29.2267 11.6465 29.39C11.8388 29.4099 10.7512 28.1352 9.79864 26.5971L23.5497 31.2301C30.7418 28.141 29.9045 28.4194 31.4486 26.7467C34.8506 23.0642 35.3268 20.9747 34.4697 14.8053C33.8903 10.641 30.8165 6.51632 27.429 5.15378Z" fill="url(#paint0_linear)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.37873 24.2463L25.1074 31.8031L29.3227 13.8808L3.29364 9.04291L1.24023 20.7184L2.37873 24.2463Z" fill="#FBFBFB"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.35905 9.44019C3.47302 9.68547 3.43945 9.74348 3.36842 9.74348C3.33644 9.74348 3.29693 9.73183 3.25993 9.71996C3.22294 9.70831 3.18822 9.69643 3.16584 9.69643C3.10303 9.69643 3.13843 9.78939 3.49449 10.2366C3.99808 10.8763 11.3936 22.0411 11.7979 22.0411C11.7999 22.0411 11.802 22.0409 11.8036 22.0402C15.2465 20.8133 29.8885 15.7877 29.8885 15.7877L28.3903 13.6055L3.35905 9.44019Z" fill="#999999"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.57227 9.16595C3.57227 9.16595 3.68258 9.73692 4.19393 10.3689C4.70209 11.0065 11.5285 21.3425 11.8711 21.2514C16.3429 20.0643 32.5671 13.7478 32.5671 13.7478L3.57227 9.16595Z" fill="#F8F8F8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.2955 31.534L2.69531 24.3522L2.77159 24.857L24.536 32.0933L24.2955 31.534Z" fill="#999999"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.37825 8.6828C8.37825 8.6828 0.519063 10.9845 4.12526 18.9973C4.12526 18.9973 2.47175 17.4834 1.48719 15.5476C1.44288 15.461 3.12836 9.4737 3.12836 9.4737L8.37825 8.6828Z" fill="url(#paint1_linear)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.12623 18.9976C3.4429 18.9857 2.3446 18.4218 1.98855 17.7392C1.54343 25.1592 4.57067 29.4924 9.3768 31.8032C7.8062 31.6232 0 27.5038 0 17.5908C0 9.16175 6.68848 1.62756 17.1554 1.28247C17.2195 1.755 11.9662 2.93986 11.7981 3.49712C11.5373 4.3643 10.9378 5.30821 10.4324 6.06508C9.74724 7.0903 11.3845 7.96707 10.1814 8.24342C8.37099 8.65885 5.95605 8.42886 4.17533 10.7438C1.49843 14.2234 3.28463 18.2042 4.12623 18.9976Z" fill="url(#paint2_radial)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.9001 1.55371C13.1217 1.03345 9.63287 3.74598 7.39333 6.89975C6.57777 8.04784 6.66684 9.10206 6.94775 10.3755C7.06834 10.9191 7.19029 11.1797 7.04344 11.734C6.96237 12.0398 6.97584 12.3253 6.87512 12.5057C6.73604 12.7551 6.55858 13.0275 6.4992 13.4752C6.35075 14.5931 6.74654 14.9492 6.99388 15.3253C7.34628 14.9754 8.03441 14.1521 9.27499 13.6604C10.5158 13.1687 11.3323 12.4294 12.8874 11.636C15.012 10.5523 17.5026 12.1965 22.2244 10.6491C23.6774 10.173 27.0166 5.22637 27.8093 5.03635C25.6018 2.59538 21.8462 1.70285 19.9001 1.55371Z" fill="url(#paint3_linear)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.4217 0.00476074C15.4217 0.00476074 14.2113 0.589426 13.6844 1.64571C14.9015 1.03226 15.6079 0.696996 15.9418 0.657028C15.9418 0.657028 15.6218 0.811873 15.2251 1.65461C15.9265 1.43011 16.1679 1.28828 16.3604 1.28623C16.3604 1.28623 16.3044 1.37484 16.2533 2.21576C15.1762 1.86678 13.1034 2.27331 12.0005 2.96394C11.6267 0.969916 15.4217 0.00476074 15.4217 0.00476074Z" fill="#3F6499"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.24 1.25326C18.1622 0.983992 16.4253 1.03698 14.9486 1.32155C15.4129 0.876423 15.9503 0.657173 15.9503 0.657173C15.2539 0.718609 14.3849 1.17332 13.639 1.65453C13.2631 1.77443 12.905 1.90986 12.5658 2.06083C12.7734 1.78722 13.0151 1.49466 13.2512 1.27016C14.128 0.436325 15.4302 0.00467751 15.4302 0.00467751C14.3189 -0.0768559 10.5994 0.875281 8.36126 5.40827C7.99448 5.85522 7.65213 6.31358 7.32599 6.77309C6.48417 7.95864 6.57643 9.0469 6.86671 10.3619C6.9905 10.9235 7.01333 11.8199 6.89115 12.3991C6.86671 12.5152 6.54811 12.8148 6.46635 13.6228C6.37888 14.4802 6.68492 14.9013 6.98661 15.2496C8.05842 13.6824 9.11562 13.3718 9.11562 13.3718C10.6157 12.7572 11.2401 12.1009 12.8458 11.2816C15.0397 10.1623 22.7114 13.8156 27.5865 12.218C29.0867 11.7265 27.0089 5.34089 27.8279 5.14494C25.5481 2.62448 22.2379 1.51225 20.24 1.25326Z" fill="url(#paint4_linear)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M35.4576 14.9986C34.2558 8.72034 28.4736 3.00843 23.8239 2.69189C21.7602 2.55143 22.394 3.60931 21.1027 4.01241C15.5381 5.74882 15.4531 6.76262 15.4531 6.76262C27.2517 7.31714 27.4305 18.9696 24.2708 21.9176C25.1599 21.7102 26.124 20.6231 27.0094 18.9166C26.9032 19.6326 26.8118 20.5109 26.6792 21.4909C26.2745 24.4814 26.7986 30.7284 18.2054 34.909C18.2054 34.909 22.9062 34.5249 25.2371 31.9007C24.2891 34.0807 21.688 35.2582 21.688 35.2582C23.6024 34.9782 28.6305 33.4944 31.8336 29.4888C35.4587 24.9546 36.549 20.701 35.4576 14.9986Z" fill="url(#paint5_linear)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.9593 26.4602C23.9593 26.4602 27.7923 25.3886 29.0274 23.3188C28.8776 25.7321 26.6885 28.2069 26.6885 28.2069C26.6885 28.2069 29.8887 27.5592 31.2533 25.3073C31.0756 27.3395 28.6118 30.0858 28.6118 30.0858C31.1306 29.6339 37.4594 25.636 35.4574 14.9983C34.275 8.71609 28.4734 3.00806 23.8234 2.69152C21.7597 2.55106 22.3935 3.60894 21.1022 4.01204C15.5381 5.74868 15.4531 6.76248 15.4531 6.76248C27.2517 7.317 30.387 13.4921 24.2708 21.7525C25.1599 21.5452 25.5165 21.0564 26.1845 20.2568C26.1842 20.2568 26.4871 23.4195 23.9593 26.4602Z" fill="url(#paint6_linear)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.80049 12.4251C8.80049 12.4251 8.11534 12.9045 7.61906 12.7823C7.03165 12.6382 6.9323 12.0691 6.9323 12.0691C6.91928 12.1856 6.90444 12.2982 6.88274 12.3991C6.85831 12.5151 6.53971 12.8148 6.45795 13.6228C6.37047 14.4802 6.6925 14.9769 6.99419 15.3252C8.066 13.758 9.10721 13.3718 9.10721 13.3718C8.69909 13.2293 8.80049 12.4251 8.80049 12.4251Z" fill="url(#paint7_linear)"/>
|
||||
<g opacity="0.6">
|
||||
<g opacity="0.6">
|
||||
<g opacity="0.2">
|
||||
<path opacity="0.2" fill-rule="evenodd" clip-rule="evenodd" d="M23.7441 2.67671C23.9046 2.63515 24.5603 2.7064 24.9906 2.89939C25.4209 3.09237 26.1629 3.43358 25.5693 3.58203C24.9757 3.73048 24.6343 3.49296 24.3376 3.24082C24.041 2.98869 23.3435 2.78063 23.7441 2.67671Z" fill="url(#paint8_linear)"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.86562 12.3314C8.86562 12.3314 12.6248 6.1365 16.0234 4.46473C16.3391 4.306 11.318 5.79941 9.29726 8.02959C8.09619 9.35513 8.73201 11.9505 8.86562 12.3314Z" fill="url(#paint9_linear)"/>
|
||||
<path opacity="0.1" fill-rule="evenodd" clip-rule="evenodd" d="M8.86523 12.3314C8.86866 12.3292 8.87254 12.3271 8.8762 12.3248C9.8482 11.7242 11.514 11.3784 12.051 10.2897C14.1183 6.09767 16.023 4.46472 16.023 4.46472C12.6245 6.13627 8.86523 12.3314 8.86523 12.3314Z" fill="#F2F2F2"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.22311 11.1985C9.22311 11.1985 8.54572 10.1591 9.52116 9.21108C10.0359 8.7116 10.8163 8.98909 10.9065 9.07884C11.2905 9.45956 11.0491 10.2632 10.7035 10.718C10.5082 10.974 9.93979 11.3727 9.22311 11.1985Z" fill="#2F4282"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.61129 11.1338C9.61129 11.1338 9.1431 10.4151 9.81775 9.76032C10.1729 9.41523 10.7123 9.60707 10.7749 9.66874C11.0401 9.93184 10.8731 10.4873 10.6345 10.8013C10.4997 10.979 10.1067 11.2544 9.61129 11.1338Z" fill="url(#paint10_linear)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.5456 10.3672C10.5351 10.6543 10.2921 10.8786 10.0028 10.8688C9.71295 10.8587 9.48594 10.6182 9.49644 10.3309C9.50672 10.0438 9.74972 9.81956 10.0398 9.82961C10.3289 9.83943 10.5555 10.0801 10.5456 10.3672Z" fill="black"/>
|
||||
<path d="M9.68961 10.5015C9.85258 10.5015 9.98469 10.3694 9.98469 10.2064C9.98469 10.0434 9.85258 9.91132 9.68961 9.91132C9.52664 9.91132 9.39453 10.0434 9.39453 10.2064C9.39453 10.3694 9.52664 10.5015 9.68961 10.5015Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M33.1814 9.44009C30.6082 5.52283 28.5694 4.52753 28.5694 4.52753C28.5694 4.52753 28.663 7.38097 30.0918 8.75722C30.2551 8.91435 28.3821 7.53284 28.3821 7.53284C28.3821 7.53284 27.9815 8.85085 28.8994 10.366C28.6329 10.0117 28.4564 9.87767 28.4564 9.87767C28.4564 9.87767 26.7273 10.675 26.2168 11.7813C25.9533 11.2838 25.7555 10.9906 25.7555 10.9906C25.7555 10.9906 24.5594 13.3774 24.7099 16.1448C24.9545 20.6444 23.8672 22.3023 23.8672 22.3023C23.8672 22.3023 26.7798 21.1848 28.1764 17.5875C28.7533 19.117 28.1588 20.7269 28.1588 20.7269C28.1588 20.7269 30.512 18.9685 31.0181 15.7636C31.5791 16.6682 31.4142 18.4739 31.4142 18.4739C31.4142 18.4739 32.9163 16.3825 32.9528 14.1051C33.6489 14.5904 33.7131 16.4864 33.7131 16.4864C33.7131 16.4864 35.9401 13.6392 33.1814 9.44009Z" fill="url(#paint11_linear)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.6808 6.70268C30.0082 5.44954 28.8217 4.65087 27.7787 4.00454C25.1781 2.39192 23.5056 2.16559 23.5056 2.16559C23.5056 2.16559 21.1057 2.61185 21.5177 3.27965C21.539 3.31391 21.5883 3.3573 21.6584 3.40709C19.5532 2.43737 18.359 4.66709 18.359 4.66709C17.156 4.59401 15.6912 5.18621 15.2641 6.77257C15.2198 6.93723 15.8029 6.84451 16.103 6.90983C17.857 7.29123 19.5082 8.11799 20.2669 8.52657C22.0318 9.47733 23.0788 11.0605 23.6835 12.2481C24.4148 13.6849 24.7135 16.2129 24.7135 16.2129C24.7135 16.2129 26.6379 13.5693 26.1782 12.212C26.9403 12.6855 27.0908 14.3744 27.0908 14.3744C27.0908 14.3744 28.3736 12.365 27.9945 10.6147C28.9841 11.2179 29.0172 12.4445 29.0172 12.4445C29.0172 12.4445 30.0249 11.0461 29.5695 8.75221C30.5652 9.54402 30.7737 10.5697 30.7737 10.5697C30.7737 10.5697 31.5875 8.39228 30.6808 6.70268Z" fill="url(#paint12_linear)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="28.9748" y1="29.3189" x2="8.19927" y2="4.09908" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#130036"/>
|
||||
<stop offset="0.2297" stop-color="#18023B"/>
|
||||
<stop offset="0.5122" stop-color="#26094A"/>
|
||||
<stop offset="0.8211" stop-color="#3D1563"/>
|
||||
<stop offset="1" stop-color="#4E1D75"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear" x1="1.48639" y1="13.8402" x2="8.37818" y2="13.8402" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#3156A8"/>
|
||||
<stop offset="0.2474" stop-color="#3351A4"/>
|
||||
<stop offset="0.5365" stop-color="#3B4397"/>
|
||||
<stop offset="0.8453" stop-color="#472C82"/>
|
||||
<stop offset="1" stop-color="#4E1D75"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="paint2_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(8.578 9.36353) scale(12.3786)">
|
||||
<stop offset="0.1654" stop-color="#14CDDA"/>
|
||||
<stop offset="0.5478" stop-color="#2061BD"/>
|
||||
<stop offset="0.6546" stop-color="#2658AC"/>
|
||||
<stop offset="0.864" stop-color="#373F81"/>
|
||||
<stop offset="1" stop-color="#432D62"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="paint3_linear" x1="6.46705" y1="8.40727" x2="27.8094" y2="8.40727" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#2061BD"/>
|
||||
<stop offset="0.1846" stop-color="#2B51AC"/>
|
||||
<stop offset="0.6826" stop-color="#442C84"/>
|
||||
<stop offset="0.9409" stop-color="#4E1D75"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint4_linear" x1="9.60982" y1="3.36979" x2="18.6751" y2="19.3209" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.0202" stop-color="#48A8E0"/>
|
||||
<stop offset="0.3883" stop-color="#2061BD"/>
|
||||
<stop offset="0.4968" stop-color="#2B51AC"/>
|
||||
<stop offset="0.7892" stop-color="#442C84"/>
|
||||
<stop offset="0.9409" stop-color="#4E1D75"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint5_linear" x1="2.85799" y1="48.9959" x2="42.8988" y2="25.7007" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.3787" stop-color="#3156A8"/>
|
||||
<stop offset="1" stop-color="#4E1D75"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint6_linear" x1="14.0492" y1="40.462" x2="37.7537" y2="10.9949" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#29ABE2"/>
|
||||
<stop offset="0.7733" stop-color="#385AA6"/>
|
||||
<stop offset="0.8575" stop-color="#414293"/>
|
||||
<stop offset="1" stop-color="#4E1D75"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint7_linear" x1="7.00851" y1="13.3643" x2="7.93109" y2="13.7193" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#B0DCD6"/>
|
||||
<stop offset="1" stop-color="#53ACE0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint8_linear" x1="25.5884" y1="3.35221" x2="24.5953" y2="2.28868" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#3092B9"/>
|
||||
<stop offset="0.2199" stop-color="#258DB6"/>
|
||||
<stop offset="0.6564" stop-color="#1685B1"/>
|
||||
<stop offset="1" stop-color="#1082AF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint9_linear" x1="11.731" y1="5.52165" x2="13.3151" y2="11.2176" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.0074" stop-color="#1398D1" stop-opacity="0"/>
|
||||
<stop offset="0.2482" stop-color="#1187C2" stop-opacity="0.6197"/>
|
||||
<stop offset="0.6422" stop-color="#3F6499" stop-opacity="0.71"/>
|
||||
<stop offset="1" stop-color="#2F4282" stop-opacity="0.5"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint10_linear" x1="10.5714" y1="10.6273" x2="9.7502" y2="10.22" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#F9C21B"/>
|
||||
<stop offset="0.1479" stop-color="#F3BA1B"/>
|
||||
<stop offset="0.3787" stop-color="#E3A41B"/>
|
||||
<stop offset="0.6634" stop-color="#C9801C"/>
|
||||
<stop offset="0.9884" stop-color="#A44E1C"/>
|
||||
<stop offset="1" stop-color="#A34C1C"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint11_linear" x1="29.9441" y1="18.8975" x2="20.857" y2="11.5081" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#409EC3"/>
|
||||
<stop offset="0.62" stop-color="#2061BD"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint12_linear" x1="25.668" y1="14.9655" x2="22.6111" y2="2.99136" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#14B2DA"/>
|
||||
<stop offset="0.4028" stop-color="#297CCC"/>
|
||||
<stop offset="0.5077" stop-color="#256FC5"/>
|
||||
<stop offset="0.6492" stop-color="#2164BF"/>
|
||||
<stop offset="0.8162" stop-color="#2061BD"/>
|
||||
<stop offset="0.9835" stop-color="#2061BD"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
3
internal/frontend/qt6/qml/icons/ic-no-connection.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 13L2 14L6.60951 9.39049L9.42104 6.57896L10.7224 5.27756L12.8435 3.15654L15 1L14 0L11.4338 2.56619C10.3363 2.19528 9.1768 2 8 2C4.99776 2 2.10791 3.271 0.0743047 5.48656C-0.0273754 5.59626 -0.0246996 5.76752 0.0823321 5.87455L1.67175 7.4637C1.78146 7.57341 1.95806 7.57341 2.06777 7.4637C2.0865 7.44524 2.09988 7.42383 2.11058 7.39975C3.61705 5.74584 5.76036 4.7962 8 4.7962C8.37819 4.7962 8.75363 4.82329 9.12372 4.87628L7.56734 6.43266C5.90389 6.54608 4.35089 7.31026 3.24238 8.56633L3.2354 8.57044C3.22366 8.5773 3.21069 8.58487 3.19957 8.59577C3.08986 8.70547 3.08986 8.88208 3.19957 8.99152L4.10403 9.89597L1 13ZM7.99994 9.11969C7.9593 9.11969 7.91877 9.12034 7.87836 9.12164L10.1916 6.80845C11.1689 7.16857 12.052 7.76806 12.7548 8.56633C12.7709 8.57436 12.7869 8.58265 12.8003 8.59577C12.91 8.70547 12.91 8.88208 12.8003 8.99152L11.2724 10.5194C11.2457 10.5462 11.2162 10.5676 11.1815 10.5809C11.1467 10.5943 11.1119 10.6023 11.0744 10.6023H11.0584C11.0519 10.6023 11.0455 10.5995 11.0391 10.5966C11.0366 10.5954 11.0341 10.5943 11.0317 10.5934C11.0299 10.5927 11.0281 10.5921 11.0263 10.5916C11.0022 10.5892 10.9781 10.5836 10.9567 10.5729C10.9436 10.5685 10.9341 10.5606 10.9238 10.5521L10.9238 10.5521L10.9166 10.5462L10.9095 10.5421L10.9045 10.5395C10.8944 10.5342 10.884 10.5288 10.8764 10.5191C10.8734 10.5176 10.872 10.5153 10.8705 10.5125C10.8693 10.5105 10.868 10.5082 10.8657 10.5057C10.8644 10.5033 10.8625 10.502 10.8606 10.5007C10.8585 10.4994 10.8564 10.498 10.855 10.495C10.1647 9.62006 9.12377 9.11969 7.99994 9.11969ZM13.8894 7.39975C13.1883 6.63018 12.3493 6.01303 11.4269 5.5731L13.4895 3.51054C14.3862 4.0424 15.2091 4.70584 15.9257 5.48656C16.0274 5.59653 16.0247 5.76752 15.9177 5.87455L14.3282 7.4637C14.2747 7.51989 14.2025 7.54692 14.1302 7.54692C14.058 7.54692 13.9857 7.51989 13.9322 7.4637C13.9135 7.44524 13.9001 7.42383 13.8894 7.39975ZM7.99998 10.2626C7.17317 10.2626 6.50154 10.9371 6.50154 11.7637C6.50154 12.5903 7.17317 13.2621 7.99998 13.2621C8.8268 13.2621 9.49843 12.5905 9.49843 11.7637C9.49843 10.9369 8.8268 10.2626 7.99998 10.2626Z" fill="#D42F34"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
29
internal/frontend/qt6/qml/icons/ic-other-mail-clients.svg
Normal file
@ -0,0 +1,29 @@
|
||||
<svg width="37" height="36" viewBox="0 0 37 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g opacity="0.7">
|
||||
<path d="M15 14H20V36H15V14Z" fill="#626262"/>
|
||||
<path d="M3 18H32.1444C32.6127 18 33 17.6217 33 17.1444V8.88969C33 5.0801 29.9109 2 26.1103 2H9.53002C5.72043 2 3 5.0891 3 8.88969V18Z" fill="url(#paint0_linear)"/>
|
||||
<path d="M20 18H32V9C32 5.69475 29.1238 2.82001 25.8185 2.82001C22.5133 2.82001 20 5.69475 20 9V18Z" fill="url(#paint1_linear)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.78225 11.2845L4.78225 16.4365C4.78225 16.7247 4.54809 16.9589 4.2599 16.9589L0.522355 16.9589C0.234159 16.9589 -3.19682e-07 16.7247 -3.07084e-07 16.4365L-2.28536e-08 9.93408C-1.02561e-08 9.64589 0.234159 9.41173 0.522355 9.41173L2.19946 9.41173L2.19946 9.41125L15.0401 9.41126C15.5534 9.41126 15.9767 9.83454 15.9767 10.3479C15.9767 10.8702 15.5534 11.2845 15.0401 11.2845L4.78225 11.2845Z" fill="url(#paint2_linear)"/>
|
||||
<path d="M20 17.9866H21.1618V18.509L31.9653 18.5823L34.9463 20.7258C34.9463 20.7258 35.7748 21.2165 36 22V23C36 23.3873 35.8379 23.8196 35.3966 24.2428C33.9916 25.4317 28.6562 25.8637 24.8646 23.0087C21.0821 20.1538 20 19 20 19V17.9866Z" fill="url(#paint3_linear)"/>
|
||||
<path d="M31.9997 18L34.9808 20.1435C34.9808 20.1435 37.0161 21.6385 35.4311 23.1695C34.0261 24.3583 28.6556 24.8503 24.864 21.9954C21.0724 19.1405 20.0001 18 20.0001 18H31.9997Z" fill="#E1E1E1"/>
|
||||
<path d="M14.8849 10.8636C14.6411 10.8636 14.4436 10.666 14.4436 10.4223C14.4436 10.1785 14.6411 9.98096 14.8849 9.98096C15.1286 9.98096 15.3262 10.1785 15.3262 10.4223C15.3262 10.666 15.1286 10.8636 14.8849 10.8636Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="17.3522" y1="5.73755" x2="17.3522" y2="18.094" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#E1E1E1"/>
|
||||
<stop offset="1" stop-color="#BEBEBE"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear" x1="23.5" y1="5.5" x2="32" y2="25.5" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#1F1F1F"/>
|
||||
<stop offset="1" stop-color="#6D6D6D" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear" x1="0.80402" y1="6.9834" x2="6.99556" y2="16.0441" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#DFDFDF"/>
|
||||
<stop offset="0.96875" stop-color="#9E9E9E"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear" x1="32.1687" y1="18.4701" x2="24.2916" y2="24.1519" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#E9E9E9"/>
|
||||
<stop offset="1" stop-color="#A5A5A5"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
3
internal/frontend/qt6/qml/icons/ic-plus.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M15 8H9V2H8V8H2V9H8V15H9V9H15V8Z" fill="#17181C"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 203 B |
9
internal/frontend/qt6/qml/icons/ic-question-circle.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="ic-question-circle">
|
||||
<g id="icon">
|
||||
<path d="M8.69 3.92C7.89347 3.70879 7.04403 3.87868 6.39 4.38C5.7528 4.88127 5.38356 5.64929 5.39 6.46H6.39C6.3828 5.95878 6.60804 5.48247 7 5.17C7.40675 4.8584 7.93577 4.75482 8.43 4.89C8.97906 5.03325 9.41216 5.45496 9.57 6C9.71599 6.49287 9.6194 7.02578 9.30972 7.43606C9.00003 7.84634 8.51401 8.0853 8 8.08H7.5V10H8.5V9C9.70091 8.76754 10.583 7.73782 10.6284 6.51546C10.6738 5.29309 9.87038 4.20082 8.69 3.88V3.92Z" fill="#17181C"/>
|
||||
<path d="M8.5 11V12H7.5V11H8.5Z" fill="#17181C"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15C11.866 15 15 11.866 15 8C15 6.14348 14.2625 4.36301 12.9497 3.05025C11.637 1.7375 9.85652 1 8 1ZM8 14C4.68629 14 2 11.3137 2 8C2 4.68629 4.68629 2 8 2C11.3137 2 14 4.68629 14 8C14 9.5913 13.3679 11.1174 12.2426 12.2426C11.1174 13.3679 9.5913 14 8 14Z" fill="#17181C"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1014 B |
10
internal/frontend/qt6/qml/icons/ic-success.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="32" cy="32" r="30" fill="url(#paint0_linear)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M45.6652 22.2252C46.6453 23.1977 46.6514 24.7806 45.6789 25.7607L29.8028 41.7606C29.3334 42.2337 28.6946 42.4997 28.0282 42.4997C27.3618 42.4998 26.723 42.2337 26.2536 41.7606L19.1297 34.5735C18.1572 33.5935 18.1633 32.0106 19.1434 31.038C20.1235 30.0655 21.7064 30.0717 22.6789 31.0517L28.0282 36.4504L42.1297 22.2389C43.1022 21.2588 44.6851 21.2527 45.6652 22.2252Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear" x1="32" y1="2" x2="32" y2="62" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#5BCB6A"/>
|
||||
<stop offset="1" stop-color="#1CB78F"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 796 B |
@ -0,0 +1,9 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="ic-three-dots-vertical">
|
||||
<g id="icon">
|
||||
<path d="M7 2C7 1.44772 7.44772 1 8 1C8.55228 1 9 1.44772 9 2C9 2.55228 8.55228 3 8 3C7.44772 3 7 2.55228 7 2Z" fill="#17181C"/>
|
||||
<path d="M7 14C7 13.4477 7.44772 13 8 13C8.55228 13 9 13.4477 9 14C9 14.5523 8.55228 15 8 15C7.44772 15 7 14.5523 7 14Z" fill="#17181C"/>
|
||||
<path d="M8 7C7.44772 7 7 7.44772 7 8C7 8.55228 7.44772 9 8 9C8.55228 9 9 8.55228 9 8C9 7.44772 8.55228 7 8 7Z" fill="#17181C"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 555 B |
5
internal/frontend/qt6/qml/icons/ic-trash.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 5H6V10H5V5Z" fill="#262A33"/>
|
||||
<path d="M8 5H9V10H8V5Z" fill="#262A33"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 2H14V3H12V13H2V3H0V2H4V0H10V2ZM9 1H5V2H9V1ZM11 12H3V3H11V12Z" fill="#262A33"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 319 B |
BIN
internal/frontend/qt6/qml/icons/img-proton-logos.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
63
internal/frontend/qt6/qml/icons/img-proton-logos.svg
Normal file
@ -0,0 +1,63 @@
|
||||
<svg width="164" height="32" viewBox="0 0 164 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.91309 8.64043C5.91309 8.2476 6.37094 8.03268 6.67315 8.28365L14.6667 14.922C15.4397 15.5639 16.5604 15.5639 17.3334 14.922L25.3269 8.28366C25.6291 8.03268 26.087 8.2476 26.087 8.64043V22.2612C26.087 23.4137 25.1526 24.3481 24 24.3481H8.00004C6.84745 24.3481 5.91309 23.4137 5.91309 22.2612V8.64043Z" fill="#6D4AFF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.7236 13.7655L18.7247 13.7664L14.699 17.3224C14.0133 17.9282 12.9882 17.9435 12.2847 17.3584L5.91309 12.0594V8.63848C5.91309 8.24565 6.37094 8.03073 6.67315 8.2817L14.6667 14.9201C15.4397 15.562 16.5604 15.562 17.3334 14.9201L18.7236 13.7655Z" fill="url(#paint0_linear_2302_47705)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.7971 11.2151V24.3481H24C25.1526 24.3481 26.087 23.4137 26.087 22.2611V8.64045C26.087 8.24762 25.6291 8.03266 25.3269 8.28368L21.7971 11.2151Z" fill="url(#paint1_linear_2302_47705)"/>
|
||||
<path d="M52.4445 8.11523C51.356 8.11523 50.4735 8.99769 50.4735 10.0862V21.9123C50.4735 23.0009 51.356 23.8834 52.4445 23.8834H62.5186V19.0653C62.5186 17.8558 63.4991 16.8753 64.7086 16.8753H69.5266V10.0862C69.5266 8.99769 68.6442 8.11523 67.5556 8.11523H52.4445Z" fill="url(#paint2_linear_2302_47705)"/>
|
||||
<path d="M52.4445 8.11523C51.356 8.11523 50.4735 8.99769 50.4735 10.0862V21.9123C50.4735 23.0009 51.356 23.8834 52.4445 23.8834H62.5186V19.0653C62.5186 17.8558 63.4991 16.8753 64.7086 16.8753H69.5266V10.0862C69.5266 8.99769 68.6442 8.11523 67.5556 8.11523H52.4445Z" fill="url(#paint3_radial_2302_47705)"/>
|
||||
<path d="M63.0661 17.6175C62.7253 18.0035 62.5185 18.5107 62.5185 19.0661V23.8842H59.124V22.9671C59.124 22.4986 59.2909 22.0454 59.5948 21.6887L63.0661 17.6152L63.0661 17.6175Z" fill="#BFD8FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M65.4751 8.11523H52.4445C51.356 8.11523 50.4735 8.99769 50.4735 10.0862V10.4695H63.9421C64.7888 10.4695 65.4751 11.1559 65.4751 12.0025V16.8753H69.5266V10.0862C69.5266 8.99769 68.6442 8.11523 67.5556 8.11523H65.6941H65.4751Z" fill="url(#paint4_linear_2302_47705)"/>
|
||||
<path d="M64.4348 21.3822H65.1279C65.1566 21.5028 65.2266 21.6096 65.3258 21.6839C65.4249 21.7583 65.547 21.7956 65.6708 21.7894C65.984 21.7894 66.1902 21.6165 66.1902 21.364C66.1902 21.1115 65.9749 20.9705 65.5487 20.9705H65.2727V20.4002H65.5116C65.9233 20.4002 66.0917 20.2486 66.0917 20.0211C66.0917 19.7936 65.9089 19.6374 65.6564 19.6374C65.5432 19.6307 65.4319 19.6684 65.3461 19.7427C65.2604 19.8169 65.2071 19.9218 65.1976 20.0348H64.5334C64.5569 19.6374 64.8701 19.0664 65.6564 19.0664C66.2881 19.0664 66.7233 19.4266 66.7233 19.9316C66.7241 20.094 66.673 20.2524 66.5775 20.3837C66.4821 20.515 66.3472 20.6125 66.1925 20.6619V20.6709C66.3729 20.7038 66.5354 20.8003 66.6505 20.943C66.7657 21.0857 66.8257 21.265 66.8196 21.4482C66.8196 21.9957 66.3184 22.3581 65.6685 22.3581C64.9777 22.3604 64.4864 21.9676 64.4348 21.3822Z" fill="#6D4AFF"/>
|
||||
<path d="M68.0302 19.1191H68.5352V22.31H67.8845V19.863L67.2574 20.2885V19.6431L68.0302 19.1191Z" fill="#6D4AFF"/>
|
||||
<path d="M93.9131 22.261V9.7393C93.9131 8.58671 94.8474 7.65234 96 7.65234H99.9139C100.309 7.65234 100.693 7.77837 101.012 8.01208L102.322 8.97377C102.64 9.20748 103.025 9.3335 103.419 9.3335H112C113.153 9.3335 114.087 10.2679 114.087 11.4205V22.261C114.087 23.4136 113.153 24.348 112 24.348H96C94.8474 24.348 93.9131 23.4136 93.9131 22.261Z" fill="url(#paint5_linear_2302_47705)"/>
|
||||
<path d="M93.9131 22.261V9.7393C93.9131 8.58671 94.8474 7.65234 96 7.65234H99.9139C100.309 7.65234 100.693 7.77837 101.012 8.01208L102.322 8.97377C102.64 9.20748 103.025 9.3335 103.419 9.3335H112C113.153 9.3335 114.087 10.2679 114.087 11.4205V22.261C114.087 23.4136 113.153 24.348 112 24.348H96C94.8474 24.348 93.9131 23.4136 93.9131 22.261Z" fill="url(#paint6_radial_2302_47705)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M103.419 9.3335H104.754H109.913H112C113.153 9.3335 114.087 10.2678 114.087 11.4205V22.261C114.087 23.4137 113.153 24.348 112 24.348H109.797V13.4588C109.797 12.5587 109.065 11.8305 108.165 11.8357L100.263 11.8812C99.9223 11.8832 99.5899 11.7781 99.3126 11.5809L97.5529 10.3295C97.2781 10.1341 96.9493 10.0292 96.6122 10.0292H93.9131V9.7393C93.9131 8.58667 94.8474 7.65234 96 7.65234H99.9139C100.309 7.65234 100.693 7.77836 101.012 8.01206L102.322 8.97379C102.64 9.20748 103.025 9.3335 103.419 9.3335Z" fill="url(#paint7_linear_2302_47705)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M146.124 24.3322C146.883 25.7082 148.834 25.7827 149.696 24.4687L157.736 12.2167C158.588 10.9174 157.773 9.17537 156.229 8.99833L140.426 7.18626C138.741 6.99307 137.542 8.78343 138.361 10.2681L146.124 24.3322Z" fill="url(#paint8_linear_2302_47705)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M146.124 24.3322C146.883 25.7082 148.834 25.7827 149.696 24.4687L157.736 12.2167C158.588 10.9174 157.773 9.17537 156.229 8.99833L140.426 7.18626C138.741 6.99307 137.542 8.78343 138.361 10.2681L146.124 24.3322Z" fill="url(#paint9_linear_2302_47705)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M147.29 21.9765L146.577 23.049C146.287 23.4836 145.641 23.4568 145.388 22.9999L146.124 24.3324C146.255 24.57 146.422 24.7688 146.612 24.9283L146.612 24.9282C147.524 25.6925 148.982 25.5558 149.696 24.4687L157.736 12.2167C158.588 10.9174 157.772 9.17539 156.228 8.99836L140.426 7.18626C138.741 6.9931 137.542 8.78346 138.361 10.2681L138.424 10.3811L151.874 11.9374C152.731 12.0366 153.184 13.0043 152.71 13.7257L147.29 21.9765Z" fill="url(#paint10_linear_2302_47705)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_2302_47705" x1="21.1305" y1="16.0853" x2="16.5321" y2="-3.54607" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#E2DBFF"/>
|
||||
<stop offset="1" stop-color="#6D4AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_2302_47705" x1="32.2319" y1="34.9858" x2="16.5393" y2="1.46296" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.271019" stop-color="#E2DBFF"/>
|
||||
<stop offset="1" stop-color="#6D4AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_2302_47705" x1="60.0001" y1="1.81548" x2="61.298" y2="20.2516" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.988738" stop-color="#6D4AFF"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="paint3_radial_2302_47705" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(63.4494 0.0669251) rotate(110.421) scale(27.2247 36.2787)">
|
||||
<stop offset="0.556057" stop-color="#54B7FF" stop-opacity="0"/>
|
||||
<stop offset="0.994421" stop-color="#54B7FF"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="paint4_linear_2302_47705" x1="69.5266" y1="16.6837" x2="57.6142" y2="0.25498" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#C8E8FF"/>
|
||||
<stop offset="0.307532" stop-color="#BDAEFF"/>
|
||||
<stop offset="1" stop-color="#6D4AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint5_linear_2302_47705" x1="104.015" y1="-0.798116" x2="105.578" y2="21.2045" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.988738" stop-color="#6D4AFF"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="paint6_radial_2302_47705" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(110.469 0.333684) rotate(116.076) scale(29.0915 45.26)">
|
||||
<stop offset="0.556057" stop-color="#FF62C0" stop-opacity="0"/>
|
||||
<stop offset="0.994421" stop-color="#FF62C0"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="paint7_linear_2302_47705" x1="87.1305" y1="4.86974" x2="112.348" y2="32.5799" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#6D4AFF"/>
|
||||
<stop offset="0.35934" stop-color="#AE8CFF"/>
|
||||
<stop offset="1" stop-color="#F8CCFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint8_linear_2302_47705" x1="149.077" y1="-3.88232" x2="149.757" y2="19.2346" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.988738" stop-color="#6D4AFF"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint9_linear_2302_47705" x1="149.21" y1="-0.682113" x2="143.559" y2="23.6447" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.47989" stop-color="#24ECC6" stop-opacity="0"/>
|
||||
<stop offset="0.994421" stop-color="#24ECC6"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint10_linear_2302_47705" x1="151.078" y1="26.3101" x2="138.551" y2="4.88666" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.0660125" stop-color="#ABFFEF"/>
|
||||
<stop offset="0.44988" stop-color="#CAC9FF"/>
|
||||
<stop offset="1" stop-color="#6D4AFF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.1 KiB |
BIN
internal/frontend/qt6/qml/icons/img-splash.png
Normal file
|
After Width: | Height: | Size: 937 KiB |
2884
internal/frontend/qt6/qml/icons/img-splash.svg
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
internal/frontend/qt6/qml/icons/img-welcome-dark.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
331
internal/frontend/qt6/qml/icons/img-welcome-dark.svg
Normal file
@ -0,0 +1,331 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="265"
|
||||
height="148"
|
||||
viewBox="0 0 265 148"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg110"
|
||||
sodipodi:docname="img-welcome-dark.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)"
|
||||
inkscape:export-filename="/home/dev/gopath/src/github.com/ProtonMail/proton-bridge/internal/frontend/qml/icons/img-welcome.png"
|
||||
inkscape:export-xdpi="400"
|
||||
inkscape:export-ydpi="400"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview112"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:pageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
showgrid="false"
|
||||
inkscape:snap-global="true"
|
||||
inkscape:snap-page="true"
|
||||
inkscape:zoom="0.69351284"
|
||||
inkscape:cx="93.004767"
|
||||
inkscape:cy="115.35475"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1041"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="18"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg110" />
|
||||
<rect
|
||||
style="fill:#1c1b24;fill-opacity:1;stroke:none;stroke-width:27.9987;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect951"
|
||||
width="265"
|
||||
height="148"
|
||||
x="0"
|
||||
y="0"
|
||||
ry="0"
|
||||
inkscape:export-filename="/home/dev/gopath/src/github.com/ProtonMail/proton-bridge/internal/frontend/qml/icons/img-welcome.png"
|
||||
inkscape:export-xdpi="400"
|
||||
inkscape:export-ydpi="400" />
|
||||
<path
|
||||
d="M221.171 147.001H44.8555C43.1441 147.001 41.8047 145.661 41.8047 143.95V142.238C41.8047 140.527 43.1441 139.188 44.8555 139.188H221.171C222.882 139.188 224.221 140.527 224.221 142.238V143.95C224.221 145.661 222.808 147.001 221.171 147.001Z"
|
||||
fill="#B0D4E5"
|
||||
id="path2" />
|
||||
<path
|
||||
d="M141.83 143.503H123.376C120.995 143.503 119.135 141.568 119.135 139.262H146.071C146.071 141.568 144.211 143.503 141.83 143.503Z"
|
||||
fill="#DAF3FF"
|
||||
id="path4" />
|
||||
<path
|
||||
d="M206.034 139.187H58.501V53.9292C58.501 49.0182 62.5191 45 67.4302 45H197.104C202.016 45 206.034 49.0182 206.034 53.9292V139.187Z"
|
||||
fill="url(#paint0_radial_8674_44242)"
|
||||
id="path6" />
|
||||
<path
|
||||
d="M199.115 139.187H66.167V55.3434C66.167 54.1529 67.1343 53.1855 68.3249 53.1855H196.883C198.074 53.1855 199.041 54.1529 199.041 55.3434V139.187H199.115Z"
|
||||
fill="url(#paint1_linear_8674_44242)"
|
||||
id="path8" />
|
||||
<path
|
||||
d="M190.805 131.286H76.1797V62.5185C76.1797 61.5234 77.028 60.7148 78.0721 60.7148H188.847C189.891 60.7148 190.739 61.5234 190.739 62.5185V131.286H190.805Z"
|
||||
fill="url(#paint2_radial_8674_44242)"
|
||||
id="path10" />
|
||||
<path
|
||||
d="M84.1558 70.7744C85.3064 70.7744 86.2392 69.8416 86.2392 68.6909C86.2392 67.5402 85.3064 66.6074 84.1558 66.6074C83.0051 66.6074 82.0723 67.5402 82.0723 68.6909C82.0723 69.8416 83.0051 70.7744 84.1558 70.7744Z"
|
||||
fill="#B0D4E5"
|
||||
id="path12" />
|
||||
<path
|
||||
d="M90.6304 70.7744C91.781 70.7744 92.7139 69.8416 92.7139 68.6909C92.7139 67.5402 91.781 66.6074 90.6304 66.6074C89.4797 66.6074 88.5469 67.5402 88.5469 68.6909C88.5469 69.8416 89.4797 70.7744 90.6304 70.7744Z"
|
||||
fill="#B0D4E5"
|
||||
id="path14" />
|
||||
<path
|
||||
d="M97.105 70.7744C98.2557 70.7744 99.1885 69.8416 99.1885 68.6909C99.1885 67.5402 98.2557 66.6074 97.105 66.6074C95.9543 66.6074 95.0215 67.5402 95.0215 68.6909C95.0215 69.8416 95.9543 70.7744 97.105 70.7744Z"
|
||||
fill="#B0D4E5"
|
||||
id="path16" />
|
||||
<path
|
||||
d="M242.633 76.3538H180.924C178.747 76.3538 177 74.5616 177 72.3891V33.9646C177 31.7922 178.774 30 180.924 30H242.606C244.783 30 246.53 31.7922 246.53 33.9646V72.3891C246.557 74.5887 244.783 76.3538 242.633 76.3538Z"
|
||||
fill="url(#paint3_linear_8674_44242)"
|
||||
id="path18" />
|
||||
<path
|
||||
d="M209.232 56.6899C210.689 57.8921 212.822 57.8921 214.28 56.6899L245.431 31.0419C244.729 30.4007 243.784 30 242.758 30H180.78C179.754 30 178.809 30.4007 178.107 31.0419L209.232 56.6899Z"
|
||||
fill="url(#paint4_linear_8674_44242)"
|
||||
id="path20" />
|
||||
<path
|
||||
d="M134.4 75C123.858 75 115.312 83.5451 115.312 94.0874V113.301C115.312 115.344 116.968 117 119.011 117H150.184C152.008 117 153.487 115.52 153.487 113.696V94.0874C153.487 83.5465 144.942 75 134.4 75ZM145.387 93.9814L137.044 101.01C135.538 102.279 133.336 102.279 131.83 101.01L123.487 93.9814C123.487 88.0172 128.323 83.1817 134.287 83.1817H134.587C140.551 83.1817 145.387 88.0172 145.387 93.9814Z"
|
||||
fill="#6D4AFF"
|
||||
id="path22" />
|
||||
<path
|
||||
d="M134.4 75C123.858 75 115.312 83.5451 115.312 94.0874V113.301C115.312 115.344 116.968 117 119.011 117H150.184C152.008 117 153.487 115.52 153.487 113.696V94.0874C153.487 83.5465 144.942 75 134.4 75ZM145.387 93.9814L137.044 101.01C135.538 102.279 133.336 102.279 131.83 101.01L123.487 93.9814C123.487 88.0172 128.323 83.1817 134.287 83.1817H134.587C140.551 83.1817 145.387 88.0172 145.387 93.9814Z"
|
||||
fill="url(#paint5_linear_8674_44242)"
|
||||
id="path24" />
|
||||
<g
|
||||
filter="url(#filter0_i_8674_44242)"
|
||||
id="g28">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M137.057 101.095C136.188 101.799 133.926 102.785 131.838 101.095C129.751 99.4048 125.418 95.6687 123.513 94.0119H123.524L123.487 93.9814C123.487 88.0172 128.323 83.1817 134.287 83.1817H134.587C140.551 83.1817 145.387 88.0172 145.387 93.9814L145.351 94.0119H145.383V117H150.184C152.008 117 153.487 115.52 153.487 113.696V94.0874C153.487 83.5465 144.942 75 134.4 75C123.858 75 115.312 83.5451 115.312 94.0874V95.2946L127.117 105.444C127.986 106.272 130.273 107.432 132.46 105.444C134.647 103.456 136.436 101.716 137.057 101.095Z"
|
||||
fill="url(#paint6_radial_8674_44242)"
|
||||
id="path26" />
|
||||
</g>
|
||||
<circle
|
||||
cx="239.278"
|
||||
cy="30.2778"
|
||||
r="15.2778"
|
||||
fill="url(#paint7_linear_8674_44242)"
|
||||
id="circle30" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M245.702 26.668C246.113 27.0766 246.116 27.7417 245.707 28.1534L238.128 35.7923C237.93 35.9911 237.662 36.1028 237.382 36.1028C237.102 36.1028 236.834 35.9911 236.636 35.7923L232.758 31.8835C232.349 31.4718 232.352 30.8067 232.764 30.3981C233.175 29.9895 233.84 29.9921 234.249 30.4039L237.382 33.5613L244.216 26.6738C244.625 26.262 245.29 26.2595 245.702 26.668Z"
|
||||
fill="white"
|
||||
id="path32" />
|
||||
<path
|
||||
d="M0.878906 69.6212C0.878906 56.0233 11.9022 45 25.5001 45V45C39.0981 45 50.1214 56.0233 50.1214 69.6212V94.2425H25.5002C11.9022 94.2425 0.878906 83.2192 0.878906 69.6212V69.6212Z"
|
||||
fill="url(#paint8_linear_8674_44242)"
|
||||
id="path34" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M31.4987 62.28V64.8004H33.9547C34.7948 64.8004 35.5056 65.4789 35.5056 66.3513V79.5019C35.5056 80.342 34.8271 81.0529 33.9547 81.0529H17.3791C16.539 81.0529 15.8281 80.3743 15.8281 79.5019V66.3513C15.8281 65.5112 16.5067 64.8004 17.3791 64.8004H19.802V62.28C19.802 59.0488 22.4192 56.4316 25.6504 56.4316C28.8815 56.4316 31.4987 59.0488 31.4987 62.28ZM29.0361 62.28V64.8004H22.3292V62.28C22.3292 59.9536 24.1059 58.9265 25.6827 58.9265C27.2594 58.9265 29.0361 59.9536 29.0361 62.28ZM25.9832 69.195C27.1141 69.195 28.0188 70.0997 28.0188 71.2306C28.0188 72.006 27.5988 72.6846 26.9526 73.0077L27.7927 76.6265H24.1738L25.0139 73.0077C24.3677 72.6523 23.9476 72.006 23.9476 71.2306C23.9476 70.0997 24.8523 69.195 25.9832 69.195Z"
|
||||
fill="white"
|
||||
id="path36" />
|
||||
<defs
|
||||
id="defs108">
|
||||
<filter
|
||||
id="filter0_i_8674_44242"
|
||||
x="114.72"
|
||||
y="75"
|
||||
width="38.7675"
|
||||
height="43.6537"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB">
|
||||
<feFlood
|
||||
flood-opacity="0"
|
||||
result="BackgroundImageFix"
|
||||
id="feFlood38" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
id="feBlend40" />
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
id="feColorMatrix42" />
|
||||
<feOffset
|
||||
dx="-0.592742"
|
||||
dy="1.65375"
|
||||
id="feOffset44" />
|
||||
<feGaussianBlur
|
||||
stdDeviation="4.44556"
|
||||
id="feGaussianBlur46" />
|
||||
<feComposite
|
||||
in2="hardAlpha"
|
||||
operator="arithmetic"
|
||||
k2="-1"
|
||||
k3="1"
|
||||
id="feComposite48" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0.462745 0 0 0 0 0.337255 0 0 0 0 1 0 0 0 0.24 0"
|
||||
id="feColorMatrix50" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="shape"
|
||||
result="effect1_innerShadow_8674_44242"
|
||||
id="feBlend52" />
|
||||
</filter>
|
||||
<radialGradient
|
||||
id="paint0_radial_8674_44242"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(202 51.5) rotate(145.641) scale(59.357 92.9759)">
|
||||
<stop
|
||||
stop-color="#292842"
|
||||
id="stop55" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#38385F"
|
||||
id="stop57" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_8674_44242"
|
||||
x1="63.7079"
|
||||
y1="144.988"
|
||||
x2="207.623"
|
||||
y2="58.7515"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#35168C"
|
||||
id="stop60" />
|
||||
<stop
|
||||
offset="0.317708"
|
||||
stop-color="#FF5454"
|
||||
id="stop62" />
|
||||
<stop
|
||||
offset="0.46875"
|
||||
stop-color="#FFDD64"
|
||||
id="stop64" />
|
||||
<stop
|
||||
offset="0.677083"
|
||||
stop-color="#BCE6FF"
|
||||
id="stop66" />
|
||||
<stop
|
||||
offset="0.911458"
|
||||
stop-color="#6983EF"
|
||||
id="stop68" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#2395FF"
|
||||
id="stop70" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="paint2_radial_8674_44242"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(188.5 63.5) rotate(135) scale(33.9411 55.1286)">
|
||||
<stop
|
||||
stop-color="#DDDBE3"
|
||||
id="stop73" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="white"
|
||||
id="stop75" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="paint3_linear_8674_44242"
|
||||
x1="211.765"
|
||||
y1="30"
|
||||
x2="211.765"
|
||||
y2="66.4208"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#C1DEF8"
|
||||
id="stop78" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#ECFAFF"
|
||||
id="stop80" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint4_linear_8674_44242"
|
||||
x1="211.769"
|
||||
y1="18.4116"
|
||||
x2="211.769"
|
||||
y2="50.4177"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#DEEBF7"
|
||||
id="stop83" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="white"
|
||||
id="stop85" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint5_linear_8674_44242"
|
||||
x1="116.679"
|
||||
y1="121.846"
|
||||
x2="122.395"
|
||||
y2="105.692"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#28B0E8"
|
||||
id="stop88" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#C5B7FF"
|
||||
stop-opacity="0"
|
||||
id="stop90" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="paint6_radial_8674_44242"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(151.237 120.479) rotate(-138.034) scale(48.3148 39.5031)">
|
||||
<stop
|
||||
stop-color="#E2DBFF"
|
||||
id="stop93" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#6D4AFF"
|
||||
id="stop95" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="paint7_linear_8674_44242"
|
||||
x1="240.861"
|
||||
y1="12.772"
|
||||
x2="241.004"
|
||||
y2="45.5557"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#2AF091"
|
||||
id="stop98" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#00C5A1"
|
||||
id="stop100" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint8_linear_8674_44242"
|
||||
x1="41.1252"
|
||||
y1="56.3637"
|
||||
x2="5.14027"
|
||||
y2="101.345"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#FFD66C"
|
||||
id="stop103" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF8E4F"
|
||||
id="stop105" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
BIN
internal/frontend/qt6/qml/icons/img-welcome.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
331
internal/frontend/qt6/qml/icons/img-welcome.svg
Normal file
@ -0,0 +1,331 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="265"
|
||||
height="148"
|
||||
viewBox="0 0 265 148"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg110"
|
||||
sodipodi:docname="img-welcome.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)"
|
||||
inkscape:export-filename="/home/dev/gopath/src/github.com/ProtonMail/proton-bridge/internal/frontend/qml/icons/img-welcome.png"
|
||||
inkscape:export-xdpi="400"
|
||||
inkscape:export-ydpi="400"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview112"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:pageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
showgrid="false"
|
||||
inkscape:snap-global="true"
|
||||
inkscape:snap-page="true"
|
||||
inkscape:zoom="0.69351284"
|
||||
inkscape:cx="93.004767"
|
||||
inkscape:cy="115.35475"
|
||||
inkscape:window-width="1916"
|
||||
inkscape:window-height="1041"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="18"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg110" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:27.9987;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect951"
|
||||
width="265"
|
||||
height="148"
|
||||
x="0"
|
||||
y="0"
|
||||
ry="0"
|
||||
inkscape:export-filename="/home/dev/gopath/src/github.com/ProtonMail/proton-bridge/internal/frontend/qml/icons/img-welcome.png"
|
||||
inkscape:export-xdpi="400"
|
||||
inkscape:export-ydpi="400" />
|
||||
<path
|
||||
d="M221.171 147.001H44.8555C43.1441 147.001 41.8047 145.661 41.8047 143.95V142.238C41.8047 140.527 43.1441 139.188 44.8555 139.188H221.171C222.882 139.188 224.221 140.527 224.221 142.238V143.95C224.221 145.661 222.808 147.001 221.171 147.001Z"
|
||||
fill="#B0D4E5"
|
||||
id="path2" />
|
||||
<path
|
||||
d="M141.83 143.503H123.376C120.995 143.503 119.135 141.568 119.135 139.262H146.071C146.071 141.568 144.211 143.503 141.83 143.503Z"
|
||||
fill="#DAF3FF"
|
||||
id="path4" />
|
||||
<path
|
||||
d="M206.034 139.187H58.501V53.9292C58.501 49.0182 62.5191 45 67.4302 45H197.104C202.016 45 206.034 49.0182 206.034 53.9292V139.187Z"
|
||||
fill="url(#paint0_radial_8674_44242)"
|
||||
id="path6" />
|
||||
<path
|
||||
d="M199.115 139.187H66.167V55.3434C66.167 54.1529 67.1343 53.1855 68.3249 53.1855H196.883C198.074 53.1855 199.041 54.1529 199.041 55.3434V139.187H199.115Z"
|
||||
fill="url(#paint1_linear_8674_44242)"
|
||||
id="path8" />
|
||||
<path
|
||||
d="M190.805 131.286H76.1797V62.5185C76.1797 61.5234 77.028 60.7148 78.0721 60.7148H188.847C189.891 60.7148 190.739 61.5234 190.739 62.5185V131.286H190.805Z"
|
||||
fill="url(#paint2_radial_8674_44242)"
|
||||
id="path10" />
|
||||
<path
|
||||
d="M84.1558 70.7744C85.3064 70.7744 86.2392 69.8416 86.2392 68.6909C86.2392 67.5402 85.3064 66.6074 84.1558 66.6074C83.0051 66.6074 82.0723 67.5402 82.0723 68.6909C82.0723 69.8416 83.0051 70.7744 84.1558 70.7744Z"
|
||||
fill="#B0D4E5"
|
||||
id="path12" />
|
||||
<path
|
||||
d="M90.6304 70.7744C91.781 70.7744 92.7139 69.8416 92.7139 68.6909C92.7139 67.5402 91.781 66.6074 90.6304 66.6074C89.4797 66.6074 88.5469 67.5402 88.5469 68.6909C88.5469 69.8416 89.4797 70.7744 90.6304 70.7744Z"
|
||||
fill="#B0D4E5"
|
||||
id="path14" />
|
||||
<path
|
||||
d="M97.105 70.7744C98.2557 70.7744 99.1885 69.8416 99.1885 68.6909C99.1885 67.5402 98.2557 66.6074 97.105 66.6074C95.9543 66.6074 95.0215 67.5402 95.0215 68.6909C95.0215 69.8416 95.9543 70.7744 97.105 70.7744Z"
|
||||
fill="#B0D4E5"
|
||||
id="path16" />
|
||||
<path
|
||||
d="M242.633 76.3538H180.924C178.747 76.3538 177 74.5616 177 72.3891V33.9646C177 31.7922 178.774 30 180.924 30H242.606C244.783 30 246.53 31.7922 246.53 33.9646V72.3891C246.557 74.5887 244.783 76.3538 242.633 76.3538Z"
|
||||
fill="url(#paint3_linear_8674_44242)"
|
||||
id="path18" />
|
||||
<path
|
||||
d="M209.232 56.6899C210.689 57.8921 212.822 57.8921 214.28 56.6899L245.431 31.0419C244.729 30.4007 243.784 30 242.758 30H180.78C179.754 30 178.809 30.4007 178.107 31.0419L209.232 56.6899Z"
|
||||
fill="url(#paint4_linear_8674_44242)"
|
||||
id="path20" />
|
||||
<path
|
||||
d="M134.4 75C123.858 75 115.312 83.5451 115.312 94.0874V113.301C115.312 115.344 116.968 117 119.011 117H150.184C152.008 117 153.487 115.52 153.487 113.696V94.0874C153.487 83.5465 144.942 75 134.4 75ZM145.387 93.9814L137.044 101.01C135.538 102.279 133.336 102.279 131.83 101.01L123.487 93.9814C123.487 88.0172 128.323 83.1817 134.287 83.1817H134.587C140.551 83.1817 145.387 88.0172 145.387 93.9814Z"
|
||||
fill="#6D4AFF"
|
||||
id="path22" />
|
||||
<path
|
||||
d="M134.4 75C123.858 75 115.312 83.5451 115.312 94.0874V113.301C115.312 115.344 116.968 117 119.011 117H150.184C152.008 117 153.487 115.52 153.487 113.696V94.0874C153.487 83.5465 144.942 75 134.4 75ZM145.387 93.9814L137.044 101.01C135.538 102.279 133.336 102.279 131.83 101.01L123.487 93.9814C123.487 88.0172 128.323 83.1817 134.287 83.1817H134.587C140.551 83.1817 145.387 88.0172 145.387 93.9814Z"
|
||||
fill="url(#paint5_linear_8674_44242)"
|
||||
id="path24" />
|
||||
<g
|
||||
filter="url(#filter0_i_8674_44242)"
|
||||
id="g28">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M137.057 101.095C136.188 101.799 133.926 102.785 131.838 101.095C129.751 99.4048 125.418 95.6687 123.513 94.0119H123.524L123.487 93.9814C123.487 88.0172 128.323 83.1817 134.287 83.1817H134.587C140.551 83.1817 145.387 88.0172 145.387 93.9814L145.351 94.0119H145.383V117H150.184C152.008 117 153.487 115.52 153.487 113.696V94.0874C153.487 83.5465 144.942 75 134.4 75C123.858 75 115.312 83.5451 115.312 94.0874V95.2946L127.117 105.444C127.986 106.272 130.273 107.432 132.46 105.444C134.647 103.456 136.436 101.716 137.057 101.095Z"
|
||||
fill="url(#paint6_radial_8674_44242)"
|
||||
id="path26" />
|
||||
</g>
|
||||
<circle
|
||||
cx="239.278"
|
||||
cy="30.2778"
|
||||
r="15.2778"
|
||||
fill="url(#paint7_linear_8674_44242)"
|
||||
id="circle30" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M245.702 26.668C246.113 27.0766 246.116 27.7417 245.707 28.1534L238.128 35.7923C237.93 35.9911 237.662 36.1028 237.382 36.1028C237.102 36.1028 236.834 35.9911 236.636 35.7923L232.758 31.8835C232.349 31.4718 232.352 30.8067 232.764 30.3981C233.175 29.9895 233.84 29.9921 234.249 30.4039L237.382 33.5613L244.216 26.6738C244.625 26.262 245.29 26.2595 245.702 26.668Z"
|
||||
fill="white"
|
||||
id="path32" />
|
||||
<path
|
||||
d="M0.878906 69.6212C0.878906 56.0233 11.9022 45 25.5001 45V45C39.0981 45 50.1214 56.0233 50.1214 69.6212V94.2425H25.5002C11.9022 94.2425 0.878906 83.2192 0.878906 69.6212V69.6212Z"
|
||||
fill="url(#paint8_linear_8674_44242)"
|
||||
id="path34" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M31.4987 62.28V64.8004H33.9547C34.7948 64.8004 35.5056 65.4789 35.5056 66.3513V79.5019C35.5056 80.342 34.8271 81.0529 33.9547 81.0529H17.3791C16.539 81.0529 15.8281 80.3743 15.8281 79.5019V66.3513C15.8281 65.5112 16.5067 64.8004 17.3791 64.8004H19.802V62.28C19.802 59.0488 22.4192 56.4316 25.6504 56.4316C28.8815 56.4316 31.4987 59.0488 31.4987 62.28ZM29.0361 62.28V64.8004H22.3292V62.28C22.3292 59.9536 24.1059 58.9265 25.6827 58.9265C27.2594 58.9265 29.0361 59.9536 29.0361 62.28ZM25.9832 69.195C27.1141 69.195 28.0188 70.0997 28.0188 71.2306C28.0188 72.006 27.5988 72.6846 26.9526 73.0077L27.7927 76.6265H24.1738L25.0139 73.0077C24.3677 72.6523 23.9476 72.006 23.9476 71.2306C23.9476 70.0997 24.8523 69.195 25.9832 69.195Z"
|
||||
fill="white"
|
||||
id="path36" />
|
||||
<defs
|
||||
id="defs108">
|
||||
<filter
|
||||
id="filter0_i_8674_44242"
|
||||
x="114.72"
|
||||
y="75"
|
||||
width="38.7675"
|
||||
height="43.6537"
|
||||
filterUnits="userSpaceOnUse"
|
||||
color-interpolation-filters="sRGB">
|
||||
<feFlood
|
||||
flood-opacity="0"
|
||||
result="BackgroundImageFix"
|
||||
id="feFlood38" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="BackgroundImageFix"
|
||||
result="shape"
|
||||
id="feBlend40" />
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
||||
result="hardAlpha"
|
||||
id="feColorMatrix42" />
|
||||
<feOffset
|
||||
dx="-0.592742"
|
||||
dy="1.65375"
|
||||
id="feOffset44" />
|
||||
<feGaussianBlur
|
||||
stdDeviation="4.44556"
|
||||
id="feGaussianBlur46" />
|
||||
<feComposite
|
||||
in2="hardAlpha"
|
||||
operator="arithmetic"
|
||||
k2="-1"
|
||||
k3="1"
|
||||
id="feComposite48" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0.462745 0 0 0 0 0.337255 0 0 0 0 1 0 0 0 0.24 0"
|
||||
id="feColorMatrix50" />
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="shape"
|
||||
result="effect1_innerShadow_8674_44242"
|
||||
id="feBlend52" />
|
||||
</filter>
|
||||
<radialGradient
|
||||
id="paint0_radial_8674_44242"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(202 51.5) rotate(145.641) scale(59.357 92.9759)">
|
||||
<stop
|
||||
stop-color="#292842"
|
||||
id="stop55" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#38385F"
|
||||
id="stop57" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_8674_44242"
|
||||
x1="63.7079"
|
||||
y1="144.988"
|
||||
x2="207.623"
|
||||
y2="58.7515"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#35168C"
|
||||
id="stop60" />
|
||||
<stop
|
||||
offset="0.317708"
|
||||
stop-color="#FF5454"
|
||||
id="stop62" />
|
||||
<stop
|
||||
offset="0.46875"
|
||||
stop-color="#FFDD64"
|
||||
id="stop64" />
|
||||
<stop
|
||||
offset="0.677083"
|
||||
stop-color="#BCE6FF"
|
||||
id="stop66" />
|
||||
<stop
|
||||
offset="0.911458"
|
||||
stop-color="#6983EF"
|
||||
id="stop68" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#2395FF"
|
||||
id="stop70" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="paint2_radial_8674_44242"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(188.5 63.5) rotate(135) scale(33.9411 55.1286)">
|
||||
<stop
|
||||
stop-color="#DDDBE3"
|
||||
id="stop73" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="white"
|
||||
id="stop75" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="paint3_linear_8674_44242"
|
||||
x1="211.765"
|
||||
y1="30"
|
||||
x2="211.765"
|
||||
y2="66.4208"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#C1DEF8"
|
||||
id="stop78" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#ECFAFF"
|
||||
id="stop80" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint4_linear_8674_44242"
|
||||
x1="211.769"
|
||||
y1="18.4116"
|
||||
x2="211.769"
|
||||
y2="50.4177"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#DEEBF7"
|
||||
id="stop83" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="white"
|
||||
id="stop85" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint5_linear_8674_44242"
|
||||
x1="116.679"
|
||||
y1="121.846"
|
||||
x2="122.395"
|
||||
y2="105.692"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#28B0E8"
|
||||
id="stop88" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#C5B7FF"
|
||||
stop-opacity="0"
|
||||
id="stop90" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
id="paint6_radial_8674_44242"
|
||||
cx="0"
|
||||
cy="0"
|
||||
r="1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(151.237 120.479) rotate(-138.034) scale(48.3148 39.5031)">
|
||||
<stop
|
||||
stop-color="#E2DBFF"
|
||||
id="stop93" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#6D4AFF"
|
||||
id="stop95" />
|
||||
</radialGradient>
|
||||
<linearGradient
|
||||
id="paint7_linear_8674_44242"
|
||||
x1="240.861"
|
||||
y1="12.772"
|
||||
x2="241.004"
|
||||
y2="45.5557"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#2AF091"
|
||||
id="stop98" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#00C5A1"
|
||||
id="stop100" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint8_linear_8674_44242"
|
||||
x1="41.1252"
|
||||
y1="56.3637"
|
||||
x2="5.14027"
|
||||
y2="101.345"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#FFD66C"
|
||||
id="stop103" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#FF8E4F"
|
||||
id="stop105" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
123
internal/frontend/qt6/qml/icons/product_logos.svg
Normal file
@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="200"
|
||||
height="25"
|
||||
viewBox="0 0 200 25"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg40"
|
||||
sodipodi:docname="product_logo.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview42"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:pageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="6.36"
|
||||
inkscape:cx="112.5"
|
||||
inkscape:cy="22.877358"
|
||||
inkscape:window-width="2556"
|
||||
inkscape:window-height="690"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="18"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg40" />
|
||||
<path
|
||||
d="m 29.2,1.42023 c 0,-0.564698 0.6795,-0.873645 1.128,-0.512874 L 42.1919,10.45 c 1.1472,0.9228 2.8105,0.9228 3.9577,0 L 58.0135,0.907358 C 58.462,0.546586 59.1416,0.855533 59.1416,1.42023 V 21 c 0,1.6569 -1.3868,3 -3.0975,3 H 32.2974 C 30.5867,24 29.2,22.6569 29.2,21 Z"
|
||||
fill="#6d4aff"
|
||||
id="path2" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="m 48.2129,8.78808 0.0017,0.00131 -5.9748,5.11171 c -1.0178,0.8708 -2.5391,0.8928 -3.5832,0.0517 L 29.2,6.33549 V 1.41794 c 0,-0.564697 0.6795,-0.873644 1.128,-0.512872 L 42.1919,10.4477 c 1.1472,0.9228 2.8105,0.9228 3.9577,0 z"
|
||||
fill="url(#paint0_linear_499_22895)"
|
||||
id="path4" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M 52.7747,5.11897 V 23.9977 h 3.2694 c 1.7107,0 3.0975,-1.3432 3.0975,-3 V 1.41796 c 0,-0.564699 -0.6796,-0.873699 -1.1281,-0.512859 z"
|
||||
fill="url(#paint1_linear_499_22895)"
|
||||
id="path6" />
|
||||
<path
|
||||
d="M 133.107,19.2709 V 4.88245 h 3.856 l 3.615,8.62775 c 0.321,0.7221 0.598,1.4619 0.829,2.2154 h 0.036 c 0.233,-0.7531 0.51,-1.4928 0.829,-2.2154 l 3.615,-8.62775 h 3.856 V 19.2709 h -2.795 V 9.63023 c -0.003,-0.31749 0.012,-0.63491 0.046,-0.95074 h -0.046 c -0.086,0.34013 -0.202,0.67219 -0.349,0.99221 l -4.006,9.4304 h -2.309 l -4.018,-9.4304 c -0.144,-0.32293 -0.268,-0.65432 -0.37,-0.99221 h -0.043 c 0.031,0.316 0.046,0.63333 0.043,0.95074 v 9.64067 z"
|
||||
fill="#6d4aff"
|
||||
id="path8" />
|
||||
<path
|
||||
d="m 159.302,9.77835 c 0.81,0.41125 1.479,1.04085 1.927,1.81265 0.48,0.8381 0.722,1.7843 0.703,2.7426 v 4.9374 h -2.447 l -0.174,-1.4809 c -0.319,0.5368 -0.787,0.9761 -1.351,1.2676 -0.605,0.3044 -1.279,0.4562 -1.961,0.4413 -0.87,0.0085 -1.725,-0.2171 -2.47,-0.6516 -0.755,-0.4435 -1.369,-1.0786 -1.777,-1.8363 -0.446,-0.834 -0.67,-1.7623 -0.651,-2.7012 -0.013,-0.924 0.231,-1.8343 0.706,-2.636 0.464,-0.7792 1.138,-1.4213 1.951,-1.85704 0.841,-0.45278 1.79,-0.68552 2.752,-0.67529 0.971,-0.01631 1.931,0.20258 2.792,0.63678 z m -0.896,6.64335 c 0.532,-0.4917 0.795,-1.1847 0.795,-2.1088 0.034,-0.7552 -0.24,-1.4931 -0.761,-2.0555 -0.249,-0.2513 -0.547,-0.4513 -0.877,-0.588 -0.331,-0.1366 -0.686,-0.207 -1.045,-0.207 -0.359,0 -0.715,0.0704 -1.045,0.207 -0.331,0.1367 -0.629,0.3367 -0.877,0.588 -0.496,0.5761 -0.768,1.3024 -0.768,2.0525 0,0.7501 0.272,1.4765 0.768,2.0526 0.245,0.2567 0.543,0.46 0.875,0.5963 0.332,0.1364 0.691,0.2027 1.051,0.1945 0.349,0.0056 0.695,-0.0562 1.018,-0.1818 0.324,-0.1256 0.618,-0.3125 0.866,-0.5498 z"
|
||||
fill="#6d4aff"
|
||||
id="path10" />
|
||||
<path
|
||||
d="m 163.439,7.29934 c -0.164,-0.14555 -0.295,-0.32321 -0.384,-0.52129 -0.088,-0.19807 -0.132,-0.41207 -0.129,-0.6279 -0.003,-0.21748 0.042,-0.43307 0.13,-0.63299 0.088,-0.19991 0.219,-0.37975 0.383,-0.52804 C 163.764,4.67587 164.204,4.5 164.663,4.5 c 0.458,0 0.898,0.17587 1.223,0.48912 0.163,0.14888 0.293,0.32891 0.381,0.52873 0.087,0.19982 0.132,0.41511 0.129,0.6323 0.003,0.21553 -0.041,0.42921 -0.129,0.62719 -0.088,0.19798 -0.218,0.37583 -0.381,0.522 -0.329,0.30624 -0.767,0.4773 -1.223,0.4773 -0.457,0 -0.895,-0.17106 -1.224,-0.4773 z m 2.603,11.97166 h -2.753 V 9.35483 h 2.753 z"
|
||||
fill="#6d4aff"
|
||||
id="path12" />
|
||||
<path
|
||||
d="m 170.8,19.2709 h -2.752 V 4.88245 h 2.752 z"
|
||||
fill="#6d4aff"
|
||||
id="path14" />
|
||||
<path
|
||||
d="M 75.9842,4.84671 H 69.1221 V 19.2441 h 2.7185 v -3.572 c 0,-0.3487 0.1431,-0.6832 0.3977,-0.9298 0.2546,-0.2467 0.6,-0.3852 0.9601,-0.3852 h 2.7858 c 1.2976,0 2.5421,-0.4993 3.4597,-1.388 0.9176,-0.8887 1.433,-2.0941 1.433,-3.35091 C 80.8814,8.99313 80.7581,8.3734 80.5142,7.79469 80.2703,7.21597 79.9106,6.6897 79.4558,6.2462 79.0011,5.8027 78.4602,5.45072 77.8644,5.21053 77.2685,4.97034 76.6295,4.8467 75.9842,4.84671 Z m 2.1406,4.7389 c -0.0025,0.59489 -0.2486,1.16459 -0.6843,1.58389 -0.4358,0.4192 -1.0256,0.6539 -1.6398,0.6523 H 71.8253 V 7.32279 h 3.9754 c 0.3048,0 0.6066,0.05814 0.8882,0.17112 0.2816,0.11297 0.5375,0.27856 0.753,0.4873 0.2155,0.20875 0.3865,0.45657 0.5031,0.72931 0.1167,0.27274 0.1767,0.56507 0.1767,0.86028 z"
|
||||
fill="#1b1340"
|
||||
id="path16" />
|
||||
<path
|
||||
d="m 81.3051,19.2443 v -5.7104 c 0,-2.331 1.4066,-4.18802 4.2169,-4.18802 0.452,-0.00632 0.9031,0.04243 1.3425,0.14513 V 11.8427 C 86.5434,11.822 86.2529,11.822 86.1397,11.822 c -1.4892,0 -2.1406,0.6575 -2.1406,1.9992 v 5.4231 z"
|
||||
fill="#1b1340"
|
||||
id="path18" />
|
||||
<path
|
||||
d="m 87.6719,14.3988 c 0,-2.867 2.2354,-5.05285 5.3453,-5.05285 3.11,0 5.3423,2.17985 5.3423,5.05285 0,2.873 -2.2354,5.0736 -5.3423,5.0736 -3.1069,0 -5.3453,-2.2066 -5.3453,-5.0736 z m 8.0272,0 c 0,-1.629 -1.1284,-2.7841 -2.6819,-2.7841 -1.5534,0 -2.6849,1.1551 -2.6849,2.7841 0,1.629 1.1284,2.7841 2.6849,2.7841 1.5565,0 2.6819,-1.1344 2.6819,-2.7841 z"
|
||||
fill="#1b1340"
|
||||
id="path20" />
|
||||
<path
|
||||
d="m 106.194,11.6353 h -2.914 v 3.6075 c 0,1.2588 0.468,1.8363 1.807,1.8363 0.129,0 0.45,0 0.853,-0.0207 v 2.1236 c -0.512,0.1452 -1.041,0.2219 -1.575,0.2281 -2.256,0 -3.791,-1.321 -3.791,-3.8149 V 11.6353 H 98.7662 V 9.56203 h 0.4496 c 0.3601,0 0.7054,-0.13855 0.9602,-0.38517 0.254,-0.24662 0.398,-0.5811 0.398,-0.92988 V 6.27441 h 2.706 v 3.27873 h 2.914 z"
|
||||
fill="#1b1340"
|
||||
id="path22" />
|
||||
<path
|
||||
d="m 107.004,14.3988 c 0,-2.867 2.236,-5.05285 5.343,-5.05285 3.107,0 5.345,2.17985 5.345,5.05285 0,2.873 -2.235,5.0736 -5.345,5.0736 -3.11,0 -5.343,-2.2066 -5.343,-5.0736 z m 8.028,0 c 0,-1.629 -1.129,-2.7841 -2.685,-2.7841 -1.557,0 -2.682,1.1551 -2.682,2.7841 0,1.629 1.128,2.7841 2.682,2.7841 1.553,0 2.685,-1.1344 2.685,-2.7841 z"
|
||||
fill="#1b1340"
|
||||
id="path24" />
|
||||
<path
|
||||
d="m 119.096,19.2443 v -5.506 c 0,-2.556 1.682,-4.39235 4.685,-4.39235 3.003,0 4.663,1.83635 4.663,4.39235 v 5.506 h -2.682 v -5.2987 c 0,-1.4246 -0.66,-2.3102 -1.981,-2.3102 -1.321,0 -1.979,0.8886 -1.979,2.3102 v 5.2987 z"
|
||||
fill="#1b1340"
|
||||
id="path26" />
|
||||
<defs
|
||||
id="defs38">
|
||||
<linearGradient
|
||||
id="paint0_linear_499_22895"
|
||||
x1="51.785198"
|
||||
y1="12.1227"
|
||||
x2="45.362202"
|
||||
y2="-16.188499"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#E2DBFF"
|
||||
id="stop28" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#6D4AFF"
|
||||
id="stop30" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_499_22895"
|
||||
x1="68.261703"
|
||||
y1="39.289398"
|
||||
x2="46.167099"
|
||||
y2="-9.4419403"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0.271019"
|
||||
stop-color="#E2DBFF"
|
||||
id="stop33" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#6D4AFF"
|
||||
id="stop35" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.4 KiB |
129
internal/frontend/qt6/qml/icons/product_logos_dark.svg
Normal file
@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="200"
|
||||
height="25"
|
||||
viewBox="0 0 200 25"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg40"
|
||||
sodipodi:docname="product_logos_dark.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04, custom)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview42"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#ffffff"
|
||||
borderopacity="1"
|
||||
inkscape:pageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="6.36"
|
||||
inkscape:cx="112.5"
|
||||
inkscape:cy="22.877358"
|
||||
inkscape:window-width="2556"
|
||||
inkscape:window-height="690"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="18"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg40" />
|
||||
<path
|
||||
d="m 29.2,1.42023 c 0,-0.564698 0.6795,-0.873645 1.128,-0.512874 L 42.1919,10.45 c 1.1472,0.9228 2.8105,0.9228 3.9577,0 L 58.0135,0.907358 C 58.462,0.546586 59.1416,0.855533 59.1416,1.42023 V 21 c 0,1.6569 -1.3868,3 -3.0975,3 H 32.2974 C 30.5867,24 29.2,22.6569 29.2,21 Z"
|
||||
fill="#6d4aff"
|
||||
id="path2" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="m 48.2129,8.78808 0.0017,0.00131 -5.9748,5.11171 c -1.0178,0.8708 -2.5391,0.8928 -3.5832,0.0517 L 29.2,6.33549 V 1.41794 c 0,-0.564697 0.6795,-0.873644 1.128,-0.512872 L 42.1919,10.4477 c 1.1472,0.9228 2.8105,0.9228 3.9577,0 z"
|
||||
fill="url(#paint0_linear_499_22895)"
|
||||
id="path4" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M 52.7747,5.11897 V 23.9977 h 3.2694 c 1.7107,0 3.0975,-1.3432 3.0975,-3 V 1.41796 c 0,-0.564699 -0.6796,-0.873699 -1.1281,-0.512859 z"
|
||||
fill="url(#paint1_linear_499_22895)"
|
||||
id="path6" />
|
||||
<path
|
||||
d="M 133.107,19.2709 V 4.88245 h 3.856 l 3.615,8.62775 c 0.321,0.7221 0.598,1.4619 0.829,2.2154 h 0.036 c 0.233,-0.7531 0.51,-1.4928 0.829,-2.2154 l 3.615,-8.62775 h 3.856 V 19.2709 h -2.795 V 9.63023 c -0.003,-0.31749 0.012,-0.63491 0.046,-0.95074 h -0.046 c -0.086,0.34013 -0.202,0.67219 -0.349,0.99221 l -4.006,9.4304 h -2.309 l -4.018,-9.4304 c -0.144,-0.32293 -0.268,-0.65432 -0.37,-0.99221 h -0.043 c 0.031,0.316 0.046,0.63333 0.043,0.95074 v 9.64067 z"
|
||||
fill="#6d4aff"
|
||||
id="path8" />
|
||||
<path
|
||||
d="m 159.302,9.77835 c 0.81,0.41125 1.479,1.04085 1.927,1.81265 0.48,0.8381 0.722,1.7843 0.703,2.7426 v 4.9374 h -2.447 l -0.174,-1.4809 c -0.319,0.5368 -0.787,0.9761 -1.351,1.2676 -0.605,0.3044 -1.279,0.4562 -1.961,0.4413 -0.87,0.0085 -1.725,-0.2171 -2.47,-0.6516 -0.755,-0.4435 -1.369,-1.0786 -1.777,-1.8363 -0.446,-0.834 -0.67,-1.7623 -0.651,-2.7012 -0.013,-0.924 0.231,-1.8343 0.706,-2.636 0.464,-0.7792 1.138,-1.4213 1.951,-1.85704 0.841,-0.45278 1.79,-0.68552 2.752,-0.67529 0.971,-0.01631 1.931,0.20258 2.792,0.63678 z m -0.896,6.64335 c 0.532,-0.4917 0.795,-1.1847 0.795,-2.1088 0.034,-0.7552 -0.24,-1.4931 -0.761,-2.0555 -0.249,-0.2513 -0.547,-0.4513 -0.877,-0.588 -0.331,-0.1366 -0.686,-0.207 -1.045,-0.207 -0.359,0 -0.715,0.0704 -1.045,0.207 -0.331,0.1367 -0.629,0.3367 -0.877,0.588 -0.496,0.5761 -0.768,1.3024 -0.768,2.0525 0,0.7501 0.272,1.4765 0.768,2.0526 0.245,0.2567 0.543,0.46 0.875,0.5963 0.332,0.1364 0.691,0.2027 1.051,0.1945 0.349,0.0056 0.695,-0.0562 1.018,-0.1818 0.324,-0.1256 0.618,-0.3125 0.866,-0.5498 z"
|
||||
fill="#6d4aff"
|
||||
id="path10" />
|
||||
<path
|
||||
d="m 163.439,7.29934 c -0.164,-0.14555 -0.295,-0.32321 -0.384,-0.52129 -0.088,-0.19807 -0.132,-0.41207 -0.129,-0.6279 -0.003,-0.21748 0.042,-0.43307 0.13,-0.63299 0.088,-0.19991 0.219,-0.37975 0.383,-0.52804 C 163.764,4.67587 164.204,4.5 164.663,4.5 c 0.458,0 0.898,0.17587 1.223,0.48912 0.163,0.14888 0.293,0.32891 0.381,0.52873 0.087,0.19982 0.132,0.41511 0.129,0.6323 0.003,0.21553 -0.041,0.42921 -0.129,0.62719 -0.088,0.19798 -0.218,0.37583 -0.381,0.522 -0.329,0.30624 -0.767,0.4773 -1.223,0.4773 -0.457,0 -0.895,-0.17106 -1.224,-0.4773 z m 2.603,11.97166 h -2.753 V 9.35483 h 2.753 z"
|
||||
fill="#6d4aff"
|
||||
id="path12" />
|
||||
<path
|
||||
d="m 170.8,19.2709 h -2.752 V 4.88245 h 2.752 z"
|
||||
fill="#6d4aff"
|
||||
id="path14" />
|
||||
<path
|
||||
d="M 75.9842,4.84671 H 69.1221 V 19.2441 h 2.7185 v -3.572 c 0,-0.3487 0.1431,-0.6832 0.3977,-0.9298 0.2546,-0.2467 0.6,-0.3852 0.9601,-0.3852 h 2.7858 c 1.2976,0 2.5421,-0.4993 3.4597,-1.388 0.9176,-0.8887 1.433,-2.0941 1.433,-3.35091 C 80.8814,8.99313 80.7581,8.3734 80.5142,7.79469 80.2703,7.21597 79.9106,6.6897 79.4558,6.2462 79.0011,5.8027 78.4602,5.45072 77.8644,5.21053 77.2685,4.97034 76.6295,4.8467 75.9842,4.84671 Z m 2.1406,4.7389 c -0.0025,0.59489 -0.2486,1.16459 -0.6843,1.58389 -0.4358,0.4192 -1.0256,0.6539 -1.6398,0.6523 H 71.8253 V 7.32279 h 3.9754 c 0.3048,0 0.6066,0.05814 0.8882,0.17112 0.2816,0.11297 0.5375,0.27856 0.753,0.4873 0.2155,0.20875 0.3865,0.45657 0.5031,0.72931 0.1167,0.27274 0.1767,0.56507 0.1767,0.86028 z"
|
||||
fill="#ffffff"
|
||||
id="path16"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m 81.3051,19.2443 v -5.7104 c 0,-2.331 1.4066,-4.18802 4.2169,-4.18802 0.452,-0.00632 0.9031,0.04243 1.3425,0.14513 V 11.8427 C 86.5434,11.822 86.2529,11.822 86.1397,11.822 c -1.4892,0 -2.1406,0.6575 -2.1406,1.9992 v 5.4231 z"
|
||||
fill="#ffffff"
|
||||
id="path18"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m 87.6719,14.3988 c 0,-2.867 2.2354,-5.05285 5.3453,-5.05285 3.11,0 5.3423,2.17985 5.3423,5.05285 0,2.873 -2.2354,5.0736 -5.3423,5.0736 -3.1069,0 -5.3453,-2.2066 -5.3453,-5.0736 z m 8.0272,0 c 0,-1.629 -1.1284,-2.7841 -2.6819,-2.7841 -1.5534,0 -2.6849,1.1551 -2.6849,2.7841 0,1.629 1.1284,2.7841 2.6849,2.7841 1.5565,0 2.6819,-1.1344 2.6819,-2.7841 z"
|
||||
fill="#ffffff"
|
||||
id="path20"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m 106.194,11.6353 h -2.914 v 3.6075 c 0,1.2588 0.468,1.8363 1.807,1.8363 0.129,0 0.45,0 0.853,-0.0207 v 2.1236 c -0.512,0.1452 -1.041,0.2219 -1.575,0.2281 -2.256,0 -3.791,-1.321 -3.791,-3.8149 V 11.6353 H 98.7662 V 9.56203 h 0.4496 c 0.3601,0 0.7054,-0.13855 0.9602,-0.38517 0.254,-0.24662 0.398,-0.5811 0.398,-0.92988 V 6.27441 h 2.706 v 3.27873 h 2.914 z"
|
||||
fill="#ffffff"
|
||||
id="path22"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m 107.004,14.3988 c 0,-2.867 2.236,-5.05285 5.343,-5.05285 3.107,0 5.345,2.17985 5.345,5.05285 0,2.873 -2.235,5.0736 -5.345,5.0736 -3.11,0 -5.343,-2.2066 -5.343,-5.0736 z m 8.028,0 c 0,-1.629 -1.129,-2.7841 -2.685,-2.7841 -1.557,0 -2.682,1.1551 -2.682,2.7841 0,1.629 1.128,2.7841 2.682,2.7841 1.553,0 2.685,-1.1344 2.685,-2.7841 z"
|
||||
fill="#ffffff"
|
||||
id="path24"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m 119.096,19.2443 v -5.506 c 0,-2.556 1.682,-4.39235 4.685,-4.39235 3.003,0 4.663,1.83635 4.663,4.39235 v 5.506 h -2.682 v -5.2987 c 0,-1.4246 -0.66,-2.3102 -1.981,-2.3102 -1.321,0 -1.979,0.8886 -1.979,2.3102 v 5.2987 z"
|
||||
fill="#ffffff"
|
||||
id="path26"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<defs
|
||||
id="defs38">
|
||||
<linearGradient
|
||||
id="paint0_linear_499_22895"
|
||||
x1="51.785198"
|
||||
y1="12.1227"
|
||||
x2="45.362202"
|
||||
y2="-16.188499"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
stop-color="#E2DBFF"
|
||||
id="stop28" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#6D4AFF"
|
||||
id="stop30" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_499_22895"
|
||||
x1="68.261703"
|
||||
y1="39.289398"
|
||||
x2="46.167099"
|
||||
y2="-9.4419403"
|
||||
gradientUnits="userSpaceOnUse">
|
||||
<stop
|
||||
offset="0.271019"
|
||||
stop-color="#E2DBFF"
|
||||
id="stop33" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#6D4AFF"
|
||||
id="stop35" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.7 KiB |
BIN
internal/frontend/qt6/qml/icons/systray-color-error.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
internal/frontend/qt6/qml/icons/systray-color-norm.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
internal/frontend/qt6/qml/icons/systray-color-update.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
internal/frontend/qt6/qml/icons/systray-color-warn.png
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
internal/frontend/qt6/qml/icons/systray-mono-error.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
internal/frontend/qt6/qml/icons/systray-mono-norm.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
internal/frontend/qt6/qml/icons/systray-mono-update.png
Normal file
|
After Width: | Height: | Size: 26 KiB |