mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-11-22 16:32:01 +03:00
324 lines
10 KiB
QML
324 lines
10 KiB
QML
import Qt.labs.platform 1.1
|
|
import Qt.labs.settings 1.0
|
|
import QtQml 2.12
|
|
import QtQuick 2.9
|
|
import QtQuick.Controls 2.2
|
|
import QtQuick.Controls.Material 2.2
|
|
import QtQuick.Layouts 1.3
|
|
import QtQuick.Window 2.2
|
|
|
|
ApplicationWindow {
|
|
id: app
|
|
|
|
readonly property string yubicoGreen: isDark() ? "#b1cf77" : "#9aca3c"
|
|
readonly property string yubicoWhite: "#ffffff"
|
|
readonly property string yubicoRed: isDark() ? "#cf6679" : "#b00020"
|
|
property string primaryColor: isDark() ? "#ffffff" : "#303030"
|
|
readonly property string defaultBackground: isDark() ? "#303030" : "#f7f8f9"
|
|
readonly property string defaultElevated: isDark() ? "#383838" : "#ffffff"
|
|
readonly property string defaultImageOverlay: isDark() ? "#565656" : "#dddddd"
|
|
readonly property string defaultForeground: isDark() ? "#fafafa" : "#565656"
|
|
property string formUnderline: isDark() ? "#737373" : "#d8d8d8"
|
|
property string formText: isDark() ? "#f0f0f0" : "#606060"
|
|
property string formPlaceholderText: isDark() ? "#808080" : "#b0b0b0"
|
|
property string formImageOverlay: isDark() ? "#d8d8d8" : "#727272"
|
|
property string formStepBackground: isDark() ? "#565656" : "#bbbbbb"
|
|
property string formHighlightItem: isDark() ? "#4a4a4a" : "#e9e9e9"
|
|
property string formButtonBorder: isDark() ? "#5f6368" : "#dadce0"
|
|
property string toolTipForeground: app.isDark() ? "#fafafa" : "#fbfbfb"
|
|
property string toolTipBackground: app.isDark() ? "#4a4a4a" : "#7f7f7f"
|
|
property var fullEmphasis: 1
|
|
property var highEmphasis: 0.87
|
|
property var lowEmphasis: 0.6
|
|
property var disabledEmphasis: 0.38
|
|
property var cardSelectedEmphasis: 0.08
|
|
property var cardHoveredEmphasis: 0.05
|
|
property var cardNormalEmphasis: 0.03
|
|
property var currentCredentialCard
|
|
property string iconFavorite: "#f7bd0c"
|
|
// Don't refresh credentials when window is minimized or hidden
|
|
// See http://doc.qt.io/qt-5/qwindow.html#Visibility-enum
|
|
property bool isInForeground: visibility != 3 && visibility != 0
|
|
|
|
function enableLogging(logLevel) {
|
|
yubiKey.enableLogging(logLevel, null);
|
|
}
|
|
|
|
function enableLoggingToFile(logLevel, logFile) {
|
|
yubiKey.enableLogging(logLevel, logFile);
|
|
}
|
|
|
|
function disableLogging() {
|
|
yubiKey.disableLogging();
|
|
}
|
|
|
|
function isDark() {
|
|
return app.Material.theme === Material.Dark;
|
|
}
|
|
|
|
function saveScreenLayout() {
|
|
settings.desktopAvailableWidth = Screen.desktopAvailableWidth;
|
|
settings.desktopAvailableHeight = Screen.desktopAvailableHeight;
|
|
}
|
|
|
|
function ensureMinimumWindowSize() {
|
|
app.width = width < minimumWidth ? minimumWidth : width;
|
|
app.height = height < minimumHeight ? minimumHeight : height;
|
|
}
|
|
|
|
function ensureValidWindowPosition() {
|
|
// If we have the same desktop dimensions as last time, use the saved position.
|
|
// If not, put the window in the middle of the screen.
|
|
var savedScreenLayout = (settings.desktopAvailableWidth === Screen.desktopAvailableWidth) && (settings.desktopAvailableHeight === Screen.desktopAvailableHeight);
|
|
app.x = (savedScreenLayout) ? settings.x : Screen.width / 2 - app.width / 2;
|
|
app.y = (savedScreenLayout) ? settings.y : Screen.height / 2 - app.height / 2;
|
|
// If app.x and app.y are outside of the available screen geometry,
|
|
// put the app in the middle of the screen.
|
|
if (!isWindowPositionInsideSomeMonitor() && (Qt.platform.os == "windows")) {
|
|
app.x = Screen.width / 2 - app.width / 2;
|
|
app.y = Screen.height / 2 - app.height / 2;
|
|
}
|
|
}
|
|
|
|
function isWindowPositionInsideSomeMonitor() {
|
|
for (var i = 0; i < monitorAreas.length; i++) {
|
|
var xMin = monitorAreas[i].xMin;
|
|
var xMax = monitorAreas[i].xMax;
|
|
var yMin = monitorAreas[i].yMin;
|
|
var yMax = monitorAreas[i].yMax;
|
|
if (app.x > xMin && app.x < xMax)
|
|
if (app.y > yMin && app.y < yMax)
|
|
return true;
|
|
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function updateTrayVisibility() {
|
|
// When the tray option is enabled, closing the last window
|
|
// doesn't actually close the application.
|
|
application.quitOnLastWindowClosed = !settings.closeToTray;
|
|
}
|
|
|
|
function calculateFavorite(credential, text) {
|
|
if (credential && credential.touch)
|
|
sysTrayIcon.showMessage(qsTr("Touch required"), qsTr("Touch your YubiKey now to generate security code."), SystemTrayIcon.NoIcon);
|
|
|
|
yubiKey.calculate(credential, function(resp) {
|
|
if (resp.success) {
|
|
clipBoard.push(resp.code.value);
|
|
sysTrayIcon.showMessage(qsTr("Copied to clipboard"), "The code for " + text + " is now in the clipboard.", SystemTrayIcon.NoIcon);
|
|
} else {
|
|
sysTrayIcon.showMessage(qsTr("Error"), "calculate failed: " + resp.error_id, SystemTrayIcon.NoIcon);
|
|
console.log("calculate failed:", resp.error_id);
|
|
}
|
|
});
|
|
}
|
|
|
|
function colorizeMatch(string, query) {
|
|
return string.replace(escapeRegExp(query.trim(), "gi"), "<span style=\"background-color:'#ffeb3b';color:'#333333';\">$&</span>") + " ";
|
|
}
|
|
|
|
function escapeRegExp(string, flags) {
|
|
return RegExp(string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&").replace(/\s+/g, "|"), flags);
|
|
}
|
|
|
|
function getFavoriteEntries() {
|
|
var favs = entriesComponent.createObject(app, {
|
|
});
|
|
for (var i = 0; i < entries.count; i++) {
|
|
var entry = entries.get(i);
|
|
if (!!entry.credential && settings.favorites.includes(entry.credential.key))
|
|
favs.append(entry);
|
|
|
|
}
|
|
return favs;
|
|
}
|
|
|
|
width: 300
|
|
height: 502
|
|
minimumWidth: 300
|
|
minimumHeight: 348
|
|
visible: false
|
|
flags: Qt.Window | Qt.WindowFullscreenButtonHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint | Qt.WindowFullscreenButtonHint
|
|
Material.theme: settings.theme
|
|
Material.primary: yubicoGreen
|
|
Material.accent: yubicoGreen
|
|
Material.foreground: defaultForeground
|
|
Material.background: defaultBackground
|
|
onIsInForegroundChanged: {
|
|
(poller.running = isInForeground || settings.closeToTray);
|
|
}
|
|
Component.onCompleted: {
|
|
updateTrayVisibility();
|
|
ensureMinimumWindowSize();
|
|
ensureValidWindowPosition();
|
|
app.visible = !(settings.closeToTray && settings.hideOnLaunch);
|
|
}
|
|
Component.onDestruction: saveScreenLayout()
|
|
font.family: robotoRegular.name
|
|
|
|
FontLoader {
|
|
id: robotoRegular
|
|
|
|
source: "../fonts/Roboto-Regular.ttf"
|
|
}
|
|
|
|
FontLoader {
|
|
id: robotoBold
|
|
|
|
source: "../fonts/Roboto-Bold.ttf"
|
|
}
|
|
|
|
FontLoader {
|
|
id: robotoItalic
|
|
|
|
source: "../fonts/Roboto-Italic.ttf"
|
|
}
|
|
|
|
FontLoader {
|
|
id: robotoMedium
|
|
|
|
source: "../fonts/Roboto-Medium.ttf"
|
|
}
|
|
|
|
FontLoader {
|
|
id: robotoLight
|
|
|
|
source: "../fonts/Roboto-Light.ttf"
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: StandardKey.Copy
|
|
enabled: !!currentCredentialCard
|
|
onActivated: app.currentCredentialCard.calculateCard(true)
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: StandardKey.Delete
|
|
enabled: !!currentCredentialCard
|
|
onActivated: app.currentCredentialCard.deleteCard()
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: "Ctrl+D" // This becomes Cmd + D on macOS
|
|
enabled: !!currentCredentialCard
|
|
onActivated: app.currentCredentialCard.toggleFavorite()
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: StandardKey.Open
|
|
enabled: !!yubiKey.currentDevice && yubiKey.currentDeviceValidated
|
|
onActivated: navigator.goToNewCredential()
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: StandardKey.Find
|
|
onActivated: toolBar.searchField.forceActiveFocus()
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: StandardKey.Preferences
|
|
onActivated: navigator.goToSettings()
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: StandardKey.Quit
|
|
context: Qt.ApplicationShortcut
|
|
onActivated: Qt.quit()
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: StandardKey.Close
|
|
onActivated: app.close()
|
|
context: Qt.ApplicationShortcut
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: StandardKey.Italic
|
|
onActivated: navigator.about()
|
|
context: Qt.ApplicationShortcut
|
|
}
|
|
|
|
Shortcut {
|
|
sequence: StandardKey.FullScreen
|
|
onActivated: visibility = visibility === Window.FullScreen ? Window.Windowed : Window.FullScreen
|
|
context: Qt.ApplicationShortcut
|
|
}
|
|
|
|
// This information is stored in the system registry on Windows,
|
|
// and in XML preferences files on macOS. On other Unix systems,
|
|
// in the absence of a standard, INI text files are used.
|
|
// See http://doc.qt.io/qt-5/qml-qt-labs-settings-settings.html#details
|
|
Settings {
|
|
id: settings
|
|
|
|
property bool useCustomReader
|
|
property string customReaderName
|
|
property bool closeToTray
|
|
property bool hideOnLaunch
|
|
property bool requireTouch: true
|
|
property int theme: Material.System
|
|
// Keep track of window and desktop dimensions.
|
|
property alias width: app.width
|
|
property alias height: app.height
|
|
property alias x: app.x
|
|
property alias y: app.y
|
|
property int desktopAvailableWidth
|
|
property int desktopAvailableHeight
|
|
property var favorites: []
|
|
|
|
onCloseToTrayChanged: updateTrayVisibility()
|
|
onThemeChanged: {
|
|
app.Material.theme = theme;
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: entriesComponent
|
|
|
|
EntriesModel {
|
|
}
|
|
|
|
}
|
|
|
|
EntriesModel {
|
|
id: entries
|
|
}
|
|
|
|
ClipBoard {
|
|
id: clipBoard
|
|
}
|
|
|
|
Timer {
|
|
id: poller
|
|
|
|
triggeredOnStart: true
|
|
interval: 1000
|
|
repeat: true
|
|
running: app.isInForeground || settings.closeToTray
|
|
onTriggered: yubiKey.poll()
|
|
}
|
|
|
|
YubiKey {
|
|
id: yubiKey
|
|
}
|
|
|
|
SystemTray {
|
|
id: sysTrayIcon
|
|
}
|
|
|
|
Navigator {
|
|
id: navigator
|
|
|
|
anchors.fill: parent
|
|
focus: true
|
|
}
|
|
|
|
header: StyledToolBar {
|
|
id: toolBar
|
|
}
|
|
|
|
}
|