Merge branch '51' into nfc-fixes

This commit is contained in:
Dag Heyman 2020-05-25 13:52:00 +02:00
commit 3a86564f02
13 changed files with 511 additions and 469 deletions

View File

@ -38,7 +38,7 @@ Pane {
NoCredentialsSection {
id: noCredentialsSection
visible: entries.count === 0 && (!!yubiKey.currentDevice)
visible: entries.count === 0 && (!!yubiKey.currentDevice) && yubiKey.currentDeviceValidated
enabled: visible
Accessible.ignored: true
}

View File

@ -0,0 +1,56 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
import QtGraphicalEffects 1.0
StyledExpansionPanel {
label: qsTr("Appearance")
description: qsTr("Change the visual appearance of the application.")
metadata: "dark light mode theme"
isTopPanel: true
ListModel {
id: themes
ListElement {
text: qsTr("System default")
value: Material.System
}
ListElement {
text: qsTr("Light mode")
value: Material.Light
}
ListElement {
text: qsTr("Dark mode")
value: Material.Dark
}
}
ColumnLayout {
RowLayout {
Layout.fillWidth: true
StyledComboBox {
id: themeComboBox
label: qsTr("Theme")
comboBox.textRole: "text"
model: themes
onCurrentIndexChanged: {
settings.theme = themes.get(currentIndex).value
}
currentIndex: {
switch (settings.theme) {
case Material.System:
return 0
case Material.Light:
return 1
case Material.Dark:
return 2
default:
return 0
}
}
}
}
}
}

View File

@ -0,0 +1,26 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
import QtGraphicalEffects 1.0
StyledExpansionPanel {
label: qsTr("Clear passwords")
description: qsTr("Delete all saved passwords.")
isEnabled: false
isBottomPanel: true
toolButtonIcon: "../images/delete.svg"
toolButtonToolTip: qsTr("Clear")
toolButton.onClicked: navigator.confirm({
"heading": qsTr("Clear passwords?"),
"message": qsTr("This will delete all saved passwords."),
"description": qsTr("A password prompt will appear the next time a YubiKey with a password is used."),
"buttonAccept": qsTr("Clear passwords"),
"acceptedCb": function() {
yubiKey.clearLocalPasswords(function (resp) {
if (resp.success) {
navigator.snackBar(qsTr("Passwords cleared"))
}
})}
})
}

View File

@ -0,0 +1,84 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
import QtGraphicalEffects 1.0
StyledExpansionPanel {
id: currentDevicePanel
label: getDeviceLabel(yubiKey.currentDevice)
description: getDeviceDescription(yubiKey.currentDevice)
keyImage: !!yubiKey.currentDevice ? yubiKey.getCurrentDeviceImage() : "../images/yubikeys-large-transparent"
isTopPanel: true
isEnabled: yubiKey.availableDevices.length > 1
function getDeviceLabel(device) {
if (!!device) {
return ("%1").arg(device.name)
} else {
return qsTr("Insert your YubiKey")
}
}
function getDeviceDescription(device) {
if (!!device) {
return qsTr("Serial number: %1").arg(!!device.serial ? device.serial : "Not available")
} else {
return qsTr("No device found")
}
}
ButtonGroup {
id: deviceButtonGroup
}
ColumnLayout {
Layout.fillWidth: true
Repeater {
model: yubiKey.availableDevices
onModelChanged: {
if (yubiKey.availableDevices.length < 2) {
currentDevicePanel.isExpanded = false
}
}
StyledRadioButton {
Layout.fillWidth: true
objectName: index
checked: !!yubiKey.currentDevice
&& modelData.serial === yubiKey.currentDevice.serial
text: getDeviceLabel(modelData)
description: getDeviceDescription(modelData)
buttonGroup: deviceButtonGroup
}
}
StyledButton {
id: selectBtn
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
text: "Select"
enabled: {
if (!!yubiKey.availableDevices && !!deviceButtonGroup.checkedButton) {
var dev = yubiKey.availableDevices[deviceButtonGroup.checkedButton.objectName]
return dev !== yubiKey.currentDevice
} else {
return false
}
}
onClicked: {
yubiKey.refreshDevicesDefault()
var dev = yubiKey.availableDevices[deviceButtonGroup.checkedButton.objectName]
yubiKey.selectCurrentSerial(dev.serial,
function (resp) {
if (resp.success) {
entries.clear()
yubiKey.currentDevice = dev
currentDevicePanel.expandAction()
} else {
console.log("select device failed", resp.error_id)
}
})
}
}
}
}

View File

@ -0,0 +1,85 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
import QtGraphicalEffects 1.0
StyledExpansionPanel {
id: customReaderPanel
label: qsTr("Custom reader")
description: qsTr("Specify a custom reader for YubiKey.")
metadata: "ccid otp slot custom readers nfc"
property bool aboutToChange: customReaderCheckbox.checked !== settings.useCustomReader
|| readerFilter.text !== settings.customReaderName && readerFilter.text.length > 0
function isValidMode() {
return aboutToChange
}
function setInterface() {
settings.useCustomReader = customReaderCheckbox.checked
settings.customReaderName = readerFilter.text
yubiKey.clearCurrentDeviceAndEntries()
yubiKey.refreshDevicesDefault()
navigator.goToSettings()
navigator.snackBar(qsTr("Interface changed"))
isExpanded = false
}
ColumnLayout {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillWidth: true
StyledCheckBox {
id: customReaderCheckbox
checked: settings.useCustomReader
text: qsTr("Enable custom reader")
description: qsTr("Useful when using a NFC reader.")
}
}
ColumnLayout {
Layout.topMargin: 16
visible: customReaderCheckbox.checked
RowLayout {
visible: yubiKey.availableReaders.length > 0
StyledComboBox {
id: connectedReaders
enabled: yubiKey.availableReaders.length > 0
visible: yubiKey.availableReaders.length > 0
label: qsTr("Connected readers")
model: yubiKey.availableReaders
}
StyledButton {
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
text: qsTr("Use as filter")
flat: true
enabled: yubiKey.availableReaders.length > 0
visible: yubiKey.availableReaders.length > 0
onClicked: readerFilter.text = connectedReaders.currentText
}
}
StyledTextField {
id: readerFilter
labelText: qsTr("Custom reader filter")
text: settings.customReaderName
}
}
RowLayout {
Layout.topMargin: 16
Item {
Layout.fillWidth: true
}
StyledButton {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
text: "Apply"
enabled: isValidMode()
onClicked: setInterface()
}
}
}

View File

@ -0,0 +1,150 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
import QtGraphicalEffects 1.0
StyledExpansionPanel {
id: passwordManagementPanel
label: qsTr("Manage password")
description: !!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword ? "Password is set" : "Password is not set"
isVisible: yubiKey.currentDeviceOathEnabled
isTopPanel: true
function clearPasswordFields() {
currentPasswordField.text = ""
newPasswordField.text = ""
confirmPasswordField.text = ""
}
function submitPassword() {
if (acceptableInput()) {
if (!!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword) {
changePassword()
} else {
setPassword()
}
}
}
function acceptableInput() {
if (!!yubiKey.currentDevice && yubiKey.currentDeviceValidated) {
if (!!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword
&& currentPasswordField.text.length == 0) {
return false
}
if (newPasswordField.text.length > 0
&& (newPasswordField.text === confirmPasswordField.text)) {
return true
}
}
return false
}
function changePassword() {
navigator.goToLoading()
yubiKey.validate(currentPasswordField.text, false, function (resp) {
if (resp.success) {
setPassword()
} else {
navigator.snackBarError(getErrorMessage(resp.error_id))
console.log("change password failed:", resp.error_id)
}
clearPasswordFields()
navigator.goToSettings()
})
}
function setPassword() {
navigator.goToLoading()
yubiKey.setPassword(newPasswordField.text, false, function (resp) {
if (resp.success) {
navigator.snackBar(qsTr("Password set"))
yubiKey.currentDevice.hasPassword = true
passwordManagementPanel.isExpanded = false
} else {
navigator.snackBarError(getErrorMessage(resp.error_id))
console.log("set password failed:", resp.error_id)
}
clearPasswordFields()
navigator.goToSettings()
})
}
function removePassword() {
navigator.goToLoading()
yubiKey.validate(currentPasswordField.text, false, function (resp) {
if (resp.success) {
yubiKey.removePassword(function (resp) {
if (resp.success) {
navigator.snackBar(qsTr("Password removed"))
yubiKey.currentDevice.hasPassword = false
passwordManagementPanel.isExpanded = false
} else {
navigator.snackBarError(getErrorMessage(resp.error_id))
console.log("remove password failed:", resp.error_id)
}
clearPasswordFields()
navigator.goToSettings()
})
} else {
navigator.snackBarError(getErrorMessage(resp.error_id))
console.log("remove password failed:", resp.error_id)
}
})
}
ColumnLayout {
StyledTextField {
id: currentPasswordField
visible: !!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword
labelText: qsTr("Current password")
echoMode: TextInput.Password
Keys.onEnterPressed: submitPassword()
Keys.onReturnPressed: submitPassword()
onSubmit: submitPassword()
}
StyledTextField {
id: newPasswordField
labelText: qsTr("New password")
echoMode: TextInput.Password
Keys.onEnterPressed: submitPassword()
Keys.onReturnPressed: submitPassword()
onSubmit: submitPassword()
}
StyledTextField {
id: confirmPasswordField
labelText: qsTr("Confirm password")
echoMode: TextInput.Password
Keys.onEnterPressed: submitPassword()
Keys.onReturnPressed: submitPassword()
onSubmit: submitPassword()
}
RowLayout {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
StyledButton {
id: removePasswordBtn
visible: !!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword
enabled: currentPasswordField.text.length > 0
text: "Remove"
onClicked: navigator.confirm({
"heading": qsTr("Remove password?"),
"description": qsTr("A password will not be required to access the accounts anymore."),
"warning": false,
"buttonAccept": qsTr("Remove password"),
"acceptedCb": function () {
removePassword()
}
})
}
StyledButton {
id: applyPassword
text: !!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword ? "Change" : "Set"
enabled: acceptableInput()
onClicked: submitPassword()
}
}
}
}

View File

@ -0,0 +1,41 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
import QtGraphicalEffects 1.0
StyledExpansionPanel {
label: qsTr("Reset")
description: qsTr("Warning: Reset will delete all accounts and restore factory defaults.")
isEnabled: false
isVisible: yubiKey.currentDeviceOathEnabled
toolButtonIcon: "../images/reset.svg"
toolButtonToolTip: qsTr("Reset device")
toolButton.onClicked: navigator.confirm({
"heading": qsTr("Reset device?"),
"message": qsTr("This will delete all accounts and restore factory defaults of your YubiKey."),
"description": qsTr("Before proceeding:<ul style=\"-qt-list-indent: 1;\"><li>There is NO going back after a factory reset.<li>If you do not know what you are doing, do NOT do this.</ul>"),
"buttonAccept": qsTr("Reset device"),
"acceptedCb": function () {
navigator.goToLoading()
yubiKey.reset(function (resp) {
if (resp.success) {
entries.clear()
navigator.snackBar(
qsTr("Reset completed"))
yubiKey.currentDeviceValidated = true
yubiKey.currentDevice.hasPassword = false
} else {
navigator.snackBarError(
navigator.getErrorMessage(
resp.error_id))
console.log("reset failed:",
resp.error_id)
}
navigator.goToSettings()
})
}
})
}

View File

@ -0,0 +1,38 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
import QtGraphicalEffects 1.0
StyledExpansionPanel {
label: Qt.platform.os === "osx" ? "Menu bar" : "System tray"
description: qsTr("Configure where and how the application is visible.")
ColumnLayout {
CheckBox {
id: sysTrayCheckbox
checked: settings.closeToTray
text: Qt.platform.os === "osx" ? qsTr("Show in menu bar") : qsTr("Show in system tray")
padding: 0
indicator.width: 16
indicator.height: 16
onCheckStateChanged: {
if(!checked) {
hideOnLaunchCheckbox.checked = false
}
settings.closeToTray = checked
}
}
CheckBox {
id: hideOnLaunchCheckbox
enabled: sysTrayCheckbox.checked
checked: settings.hideOnLaunch
text: qsTr("Hide on launch")
padding: 0
indicator.width: 16
indicator.height: 16
onCheckStateChanged: settings.hideOnLaunch = checked
}
}
}

View File

@ -23,476 +23,35 @@ Flickable {
Keys.onEscapePressed: navigator.home()
function getDeviceLabel(device) {
if (!!device) {
return ("%1").arg(device.name)
} else {
return qsTr("Insert your YubiKey")
}
}
function getDeviceDescription(device) {
if (!!device) {
return qsTr("Serial number: %1").arg(!!device.serial ? device.serial : "Not available")
} else {
return qsTr("No device found")
}
}
function clearPasswordFields() {
currentPasswordField.text = ""
newPasswordField.text = ""
confirmPasswordField.text = ""
}
function submitPassword() {
if (acceptableInput()) {
if (!!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword) {
changePassword()
} else {
setPassword()
}
}
}
function acceptableInput() {
if (!!yubiKey.currentDevice && yubiKey.currentDeviceValidated) {
if (!!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword
&& currentPasswordField.text.length == 0) {
return false
}
if (newPasswordField.text.length > 0
&& (newPasswordField.text === confirmPasswordField.text)) {
return true
}
}
return false
}
function changePassword() {
navigator.goToLoading()
yubiKey.validate(currentPasswordField.text, false, function (resp) {
if (resp.success) {
setPassword()
} else {
navigator.snackBarError(getErrorMessage(resp.error_id))
console.log("change password failed:", resp.error_id)
}
clearPasswordFields()
navigator.goToSettings()
})
}
function setPassword() {
navigator.goToLoading()
yubiKey.setPassword(newPasswordField.text, false, function (resp) {
if (resp.success) {
navigator.snackBar(qsTr("Password set"))
yubiKey.currentDevice.hasPassword = true
passwordManagementPanel.isExpanded = false
} else {
navigator.snackBarError(getErrorMessage(resp.error_id))
console.log("set password failed:", resp.error_id)
}
clearPasswordFields()
navigator.goToSettings()
})
}
function removePassword() {
navigator.goToLoading()
yubiKey.validate(currentPasswordField.text, false, function (resp) {
if (resp.success) {
yubiKey.removePassword(function (resp) {
if (resp.success) {
navigator.snackBar(qsTr("Password removed"))
yubiKey.currentDevice.hasPassword = false
passwordManagementPanel.isExpanded = false
} else {
navigator.snackBarError(getErrorMessage(resp.error_id))
console.log("remove password failed:", resp.error_id)
}
clearPasswordFields()
navigator.goToSettings()
})
} else {
navigator.snackBarError(getErrorMessage(resp.error_id))
console.log("remove password failed:", resp.error_id)
}
})
}
property string title: qsTr("")
ListModel {
id: themes
ListElement {
text: qsTr("System default")
value: Material.System
}
ListElement {
text: qsTr("Light mode")
value: Material.Light
}
ListElement {
text: qsTr("Dark mode")
value: Material.Dark
}
}
ColumnLayout {
id: content
anchors.fill: parent
Layout.fillHeight: true
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
spacing: 0
StyledExpansionContainer {
id: keyPane
sectionTitle: qsTr("Device")
StyledExpansionPanel {
id: currentDevicePanel
label: getDeviceLabel(yubiKey.currentDevice)
description: getDeviceDescription(yubiKey.currentDevice)
keyImage: !!yubiKey.currentDevice ? yubiKey.getCurrentDeviceImage() : "../images/yubikeys-large-transparent"
isTopPanel: true
Layout.fillWidth: true
isEnabled: yubiKey.availableDevices.length > 1
ButtonGroup {
id: deviceButtonGroup
}
ColumnLayout {
Layout.fillWidth: true
Repeater {
model: yubiKey.availableDevices
onModelChanged: {
if (yubiKey.availableDevices.length < 2) {
currentDevicePanel.isExpanded = false
}
}
StyledRadioButton {
Layout.fillWidth: true
objectName: index
checked: !!yubiKey.currentDevice
&& modelData.serial === yubiKey.currentDevice.serial
text: getDeviceLabel(modelData)
description: getDeviceDescription(modelData)
buttonGroup: deviceButtonGroup
}
}
StyledButton {
id: selectBtn
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
text: "Select"
enabled: {
if (!!yubiKey.availableDevices && !!deviceButtonGroup.checkedButton) {
var dev = yubiKey.availableDevices[deviceButtonGroup.checkedButton.objectName]
return dev !== yubiKey.currentDevice
} else {
return false
}
}
onClicked: {
yubiKey.refreshDevicesDefault()
var dev = yubiKey.availableDevices[deviceButtonGroup.checkedButton.objectName]
yubiKey.selectCurrentSerial(dev.serial,
function (resp) {
if (resp.success) {
entries.clear()
yubiKey.currentDevice = dev
currentDevicePanel.expandAction()
} else {
console.log("select device failed", resp.error_id)
}
})
}
}
}
}
StyledExpansionPanel {
id: passwordManagementPanel
label: !!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword ? qsTr("Change password") : qsTr("Set password")
description: qsTr("For additional security the YubiKey may be protected with a password.")
isVisible: yubiKey.currentDeviceOathEnabled()
ColumnLayout {
StyledTextField {
id: currentPasswordField
visible: !!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword
labelText: qsTr("Current password")
echoMode: TextInput.Password
Keys.onEnterPressed: submitPassword()
Keys.onReturnPressed: submitPassword()
onSubmit: submitPassword()
}
StyledTextField {
id: newPasswordField
labelText: qsTr("New password")
echoMode: TextInput.Password
Keys.onEnterPressed: submitPassword()
Keys.onReturnPressed: submitPassword()
onSubmit: submitPassword()
}
StyledTextField {
id: confirmPasswordField
labelText: qsTr("Confirm password")
echoMode: TextInput.Password
Keys.onEnterPressed: submitPassword()
Keys.onReturnPressed: submitPassword()
onSubmit: submitPassword()
}
RowLayout {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
StyledButton {
id: removePasswordBtn
visible: !!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword
enabled: currentPasswordField.text.length > 0
text: "Remove"
onClicked: navigator.confirm({
"heading": qsTr("Remove password?"),
"description": qsTr("A password will not be required to access the accounts anymore."),
"warning": false,
"buttonAccept": qsTr("Remove password"),
"acceptedCb": function () {
removePassword()
}
})
}
StyledButton {
id: applyPassword
text: !!yubiKey.currentDevice && yubiKey.currentDevice.hasPassword ? "Change" : "Set"
enabled: acceptableInput()
onClicked: submitPassword()
}
}
}
}
StyledExpansionPanel {
label: qsTr("Reset")
description: qsTr("Warning: Reset will delete all accounts and restore factory defaults.")
isEnabled: false
isVisible: yubiKey.currentDeviceOathEnabled()
toolButtonIcon: "../images/reset.svg"
toolButtonToolTip: qsTr("Reset device")
toolButton.onClicked: navigator.confirm({
"heading": qsTr("Reset device?"),
"message": qsTr("This will delete all accounts and restore factory defaults of your YubiKey."),
"description": qsTr("Before proceeding:<ul style=\"-qt-list-indent: 1;\"><li>There is NO going back after a factory reset.<li>If you do not know what you are doing, do NOT do this.</ul>"),
"buttonAccept": qsTr("Reset device"),
"acceptedCb": function () {
navigator.goToLoading()
yubiKey.reset(function (resp) {
if (resp.success) {
entries.clear()
navigator.snackBar(
qsTr("Reset completed"))
yubiKey.currentDeviceValidated = true
yubiKey.currentDevice.hasPassword = false
} else {
navigator.snackBarError(
navigator.getErrorMessage(
resp.error_id))
console.log("reset failed:",
resp.error_id)
}
navigator.goToSettings()
})
}
})
}
title: qsTr("Device")
SettingsPanelCurrentDevice {}
}
StyledExpansionContainer {
id: appPane
sectionTitle: qsTr("Application")
title: qsTr("Application")
StyledExpansionPanel {
label: qsTr("Appearance")
description: qsTr("Change the visual appearance of the application.")
metadata: "dark light mode theme"
isTopPanel: true
ColumnLayout {
RowLayout {
Layout.fillWidth: true
StyledComboBox {
id: themeComboBox
label: qsTr("Theme")
comboBox.textRole: "text"
model: themes
onCurrentIndexChanged: {
settings.theme = themes.get(currentIndex).value
}
currentIndex: {
switch (settings.theme) {
case Material.System:
return 0
case Material.Light:
return 1
case Material.Dark:
return 2
default:
return 0
}
}
}
}
}
}
StyledExpansionPanel {
id: interfacePanel
label: qsTr("Custom reader")
description: qsTr("Specify a custom reader for YubiKey.")
metadata: "ccid otp slot custom readers nfc"
property bool aboutToChange: customReaderCheckbox.checked !== settings.useCustomReader
|| readerFilter.text !== settings.customReaderName && readerFilter.text.length > 0
function isValidMode() {
return aboutToChange
}
function setInterface() {
settings.useCustomReader = customReaderCheckbox.checked
settings.customReaderName = readerFilter.text
yubiKey.clearCurrentDeviceAndEntries()
yubiKey.refreshDevicesDefault()
navigator.goToSettings()
navigator.snackBar(qsTr("Interface changed"))
interfacePanel.isExpanded = false
}
ColumnLayout {
CheckBox {
id: customReaderCheckbox
checked: settings.useCustomReader
text: qsTr("Enable custom reader")
padding: 0
indicator.width: 16
indicator.height: 16
}
Label {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
Layout.fillWidth: true
font.pixelSize: 13
color: primaryColor
opacity: lowEmphasis
text: "Specify a custom reader, useful for example when using a NFC reader."
textFormat: TextEdit.RichText
wrapMode: Text.WordWrap
elide: Text.ElideRight
lineHeight: 1.1
}
}
ColumnLayout {
Layout.topMargin: 8
visible: customReaderCheckbox.checked
RowLayout {
visible: yubiKey.availableReaders.length > 0
StyledComboBox {
id: connectedReaders
enabled: yubiKey.availableReaders.length > 0
visible: yubiKey.availableReaders.length > 0
label: qsTr("Connected readers")
model: yubiKey.availableReaders
}
StyledButton {
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
text: qsTr("Use as filter")
flat: true
enabled: yubiKey.availableReaders.length > 0
visible: yubiKey.availableReaders.length > 0
onClicked: readerFilter.text = connectedReaders.currentText
}
}
StyledTextField {
id: readerFilter
labelText: qsTr("Custom reader filter")
text: settings.customReaderName
}
}
StyledButton {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
text: "Apply"
enabled: interfacePanel.isValidMode()
onClicked: interfacePanel.setInterface()
}
}
StyledExpansionPanel {
label: Qt.platform.os === "osx" ? "Menu bar" : "System tray"
description: qsTr("Configure where and how the application is visible.")
ColumnLayout {
CheckBox {
id: sysTrayCheckbox
checked: settings.closeToTray
text: Qt.platform.os === "osx" ? qsTr("Show in menu bar") : qsTr("Show in system tray")
padding: 0
indicator.width: 16
indicator.height: 16
onCheckStateChanged: {
if(!checked) {
hideOnLaunchCheckbox.checked = false
}
settings.closeToTray = checked
}
}
CheckBox {
id: hideOnLaunchCheckbox
enabled: sysTrayCheckbox.checked
checked: settings.hideOnLaunch
text: qsTr("Hide on launch")
padding: 0
indicator.width: 16
indicator.height: 16
onCheckStateChanged: settings.hideOnLaunch = checked
}
}
}
StyledExpansionPanel {
label: qsTr("Clear passwords")
description: qsTr("Delete all saved passwords.")
isEnabled: false
isBottomPanel: true
toolButtonIcon: "../images/delete.svg"
toolButtonToolTip: qsTr("Clear")
toolButton.onClicked: navigator.confirm({
"heading": qsTr("Clear passwords?"),
"message": qsTr("This will delete all saved passwords."),
"description": qsTr("A password prompt will appear the next time a YubiKey with a password is used."),
"buttonAccept": qsTr("Clear passwords"),
"acceptedCb": function() {
yubiKey.clearLocalPasswords(function (resp) {
if (resp.success) {
navigator.snackBar(qsTr("Passwords cleared"))
}
})}
})
}
SettingsPanelAppearance {}
SettingsPanelCustomReader {}
SettingsPanelSystemTray {}
SettingsPanelClearPasswords {}
}
StyledExpansionContainer {
title: qsTr("Security Codes (OATH)")
SettingsPanelPasswordMgmt {}
SettingsPanelResetDevice {}
}
}
}

View File

@ -13,10 +13,11 @@ Item {
property alias checked: control.checked
height: 40
Layout.bottomMargin: 8
Layout.bottomMargin: 16
activeFocusOnTab: true
RowLayout {
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
CheckBox {
id: control

View File

@ -12,7 +12,7 @@ Pane {
readonly property int dynamicWidth: 648
readonly property int dynamicMargin: 32
property string sectionTitle
property string title
Layout.alignment: Qt.AlignCenter | Qt.AlignTop
Layout.fillWidth: true
@ -22,7 +22,7 @@ Pane {
visible: {
if (toolBar.searchField.text.length > 0) {
for (var i = 0; i < children.length; ++i) {
if (!!children[i] && children[i].toString().startsWith("StyledExpansionPanel") && children[i].visible) {
if (!!children[i] && children[i].toString().startsWith("SettingsPanel") && children[i].visible) {
return true
}
}
@ -39,7 +39,7 @@ Pane {
RowLayout {
Label {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
text: sectionTitle
text: title
color: Material.primary
font.pixelSize: 14
font.weight: Font.Medium

View File

@ -36,7 +36,7 @@ Pane {
Layout.alignment: Qt.AlignCenter | Qt.AlignTop
Layout.fillWidth: true
Layout.minimumHeight: isExpanded ? panelHeader.height + expandedContent.height + 40 : panelHeader.height + 20
Layout.minimumHeight: isExpanded ? panelHeader.height + expandedContent.height + 48 : panelHeader.height + 19
Layout.maximumWidth: dynamicWidth + dynamicMargin
Layout.leftMargin: -16
@ -55,7 +55,7 @@ Pane {
function expandAction() {
function collapseAll() {
for (var i = 0; i < parent.children.length; ++i) {
if (!!parent.children[i] && parent.children[i].toString().startsWith("StyledExpansionPanel")) {
if (!!parent.children[i] && parent.children[i].toString().startsWith("SettingsPanel")) {
parent.children[i].isExpanded = false
}
}
@ -72,14 +72,15 @@ Pane {
}
MouseArea {
id: panelMouseArea
onClicked: expandAction()
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: -16
anchors.rightMargin: -16
anchors.topMargin: -16
height: panelHeader.height + 40
anchors.topMargin: -12
height: panelHeader.implicitHeight + 19
enabled: isEnabled
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
}
@ -156,15 +157,15 @@ Pane {
}
Label {
id: panelDescription
Layout.alignment: Qt.AlignRight | Qt.AlignTop
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillWidth: true
font.pixelSize: 13
color: primaryColor
opacity: lowEmphasis
text: searchQuery.length > 0 ? colorizeMatch(description, searchQuery) : description
textFormat: TextEdit.RichText
textFormat: searchQuery.length > 0 ? TextEdit.RichText : TextEdit.PlainText
wrapMode: Text.WordWrap
maximumLineCount: isExpanded ? 4 : 2
maximumLineCount: isExpanded ? 4 : 1
elide: Text.ElideRight
lineHeight: 1.1
visible: description

View File

@ -264,7 +264,8 @@ Python {
// If oath is enabled, do a calculate all
if (currentDeviceOathEnabled) {
calculateAll(navigator.goToCredentialsIfNotInSettings)
} else {
} else {
currentDeviceValidated = true
navigator.goToCredentialsIfNotInSettings()
}
} else {