mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-11 05:06:51 +00:00
Fixed issues introduced by upgrading to Qt 5.15. WIP: upgrade to Qt 6 WIP: QML fixes. [sklp-ci] WIP: macOS font fix. WIP: backend is a now a singleton. WIP: remove version number of import. WIP: fixed missing Action in qmldir. WIP: fixed errors on program exit. WIP: CMake detects host arch on mac if not specified.
290 lines
9.8 KiB
QML
290 lines
9.8 KiB
QML
// 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
|
|
import QtQuick
|
|
import QtQuick.Window
|
|
import Qt.labs.platform
|
|
|
|
import Proton
|
|
import Notifications
|
|
|
|
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 title: "Proton Mail Bridge"
|
|
|
|
property Notifications _notifications: Notifications {
|
|
id: notifications
|
|
frontendMain: mainWindow
|
|
frontendStatus: statusWindow
|
|
frontendTray: trayIcon
|
|
}
|
|
|
|
property MainWindow _mainWindow: MainWindow {
|
|
id: mainWindow
|
|
visible: false
|
|
|
|
title: root.title
|
|
notifications: root._notifications
|
|
|
|
onVisibleChanged: {
|
|
Backend.dockIconVisible = visible
|
|
}
|
|
|
|
Connections {
|
|
target: Backend
|
|
function onCacheUnavailable() {
|
|
mainWindow.showAndRise()
|
|
}
|
|
function onColorSchemeNameChanged(scheme) { root.setColorScheme() }
|
|
}
|
|
}
|
|
|
|
property StatusWindow _statusWindow: StatusWindow {
|
|
id: statusWindow
|
|
visible: false
|
|
|
|
title: root.title
|
|
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(reason) {
|
|
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 `qrc:/qml/icons/systray-${color}-${level}.png`
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
if (!Backend) {
|
|
console.log("Backend not loaded")
|
|
}
|
|
|
|
root.setColorScheme()
|
|
|
|
|
|
if (!Backend.users) {
|
|
console.log("users not loaded")
|
|
}
|
|
|
|
var c = Backend.users.count
|
|
var u = 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 (Backend.showOnStartup) {
|
|
mainWindow.showAndRise()
|
|
}
|
|
|
|
Backend.guiReady()
|
|
}
|
|
|
|
function setColorScheme() {
|
|
if (Backend.colorSchemeName == "light") ProtonStyle.currentStyle = ProtonStyle.lightStyle
|
|
if (Backend.colorSchemeName == "dark") ProtonStyle.currentStyle = ProtonStyle.darkStyle
|
|
}
|
|
}
|