- hypr/apps.lua - hypr/autostart.lua - hypr/envs.lua - hypr/hyprland.lua - hypr/hyprsunset.conf - hypr/input.lua - hypr/looknfeel.lua - hypr/omasettings.lua - hypr/xdph.conf - omarchy/branding/about.txt - omarchy/branding/screensaver.txt - omarchy/extensions/omarchy-menu.jsonc - omarchy/hooks/battery-low.d/play-warning-sound.sample - omarchy/hooks/font-set.d/show-font-notification.sample - omarchy/hooks/post-boot.d/weather.sample - omarchy/hooks/post-update.d/install-voxtype.hook - omarchy/hooks/post-update.d/setup-agent.hook - omarchy/hooks/post-update.d/setup-fingerprint.hook - omarchy/hooks/post-update.d/show-update-notification.sample - omarchy/hooks/pre-refresh-pacman.d/add-custom-repo.sample - omarchy/hooks/theme-set.d/show-theme-notification.sample - omarchy/shell.json - omarchy/shell.toml - omarchy/theme.name - omarchy/themes/azure-glow/README.md - omarchy/themes/azure-glow/alacritty.toml - omarchy/themes/azure-glow/btop.theme - omarchy/themes/azure-glow/hyprland.conf - omarchy/themes/azure-glow/hyprlock.conf - omarchy/themes/azure-glow/icons.theme - … 269 more
333 lines
10 KiB
QML
333 lines
10 KiB
QML
import QtQuick
|
|
import qs.Commons
|
|
import qs.Ui
|
|
import "BitwardenModel.js" as Model
|
|
|
|
// The first step of an SSH request when the vault is locked. Uses the same
|
|
// layout, pulsing fingerprint animation, and unlock controls as the panel's
|
|
// unlock screen, while keeping the SSH request context visible.
|
|
Column {
|
|
id: screen
|
|
|
|
required property var panel
|
|
property bool active: false
|
|
|
|
visible: active && panel.sshUnlockRequest !== null
|
|
width: parent ? parent.width : 0
|
|
spacing: Style.space(12)
|
|
|
|
onVisibleChanged: if (!visible && eyeBtnUnlock) eyeBtnUnlock.revealed = false
|
|
onActiveChanged: if (!active && eyeBtnUnlock) eyeBtnUnlock.revealed = false
|
|
|
|
component UnlockCaption: Text {
|
|
textFormat: Text.PlainText
|
|
width: parent ? parent.width : 0
|
|
color: screen.panel.dim
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.font.caption
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
|
|
function focusDefault() {
|
|
if (!screen.active || !screen.visible) return
|
|
screen.panel.prepareUnlock()
|
|
if (screen.panel.fingerprintReady) screen.panel.startFingerprintUnlock()
|
|
Qt.callLater(function() {
|
|
if (!screen.active || screen.panel.status !== "locked") return
|
|
if (screen.panel.pinReady) pinField.forceActiveFocus()
|
|
else passwordField.forceActiveFocus()
|
|
})
|
|
}
|
|
|
|
// Centered header matching Panel.qml Screen 2
|
|
Column {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
spacing: Style.space(6)
|
|
|
|
Text {
|
|
id: fingerprintIcon
|
|
textFormat: Text.PlainText
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: screen.panel.fingerprintScanning ? "" : ""
|
|
color: screen.panel.fingerprintScanning ? Color.accent : screen.panel.fg
|
|
opacity: 0.85
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.space(38)
|
|
|
|
SequentialAnimation on opacity {
|
|
running: screen.panel.fingerprintScanning
|
|
loops: Animation.Infinite
|
|
NumberAnimation { to: 0.35; duration: 700; easing.type: Easing.InOutQuad }
|
|
NumberAnimation { to: 0.95; duration: 700; easing.type: Easing.InOutQuad }
|
|
onStopped: fingerprintIcon.opacity = 0.85
|
|
}
|
|
}
|
|
|
|
Text {
|
|
textFormat: Text.PlainText
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: screen.panel.status === "unlocked"
|
|
? "Loading SSH keys"
|
|
: (screen.panel.fingerprintReady ? "Unlock Vault" : "Enter Master Password")
|
|
color: screen.panel.fg
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.font.title
|
|
font.bold: true
|
|
}
|
|
|
|
Text {
|
|
textFormat: Text.PlainText
|
|
visible: screen.panel.userEmail !== ""
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
text: screen.panel.userEmail
|
|
color: screen.panel.dim
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.font.bodySmall
|
|
}
|
|
}
|
|
|
|
UnlockCaption {
|
|
text: {
|
|
var request = screen.panel.sshUnlockRequest
|
|
var prefix = "Vault needs to be unlocked first: "
|
|
if (!request) return "Vault needs to be unlocked first."
|
|
if (request.keyName !== "") {
|
|
return prefix + request.keyName + " is needed by " + request.processName + "."
|
|
}
|
|
return prefix + request.processName + " is asking which SSH keys are available."
|
|
}
|
|
horizontalAlignment: Text.AlignHCenter
|
|
color: screen.panel.fg
|
|
}
|
|
|
|
UnlockCaption {
|
|
text: "Unlocking only loads the key. You will still approve the signing request separately."
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
|
|
// Fingerprint status / prompt
|
|
Text {
|
|
textFormat: Text.PlainText
|
|
visible: screen.panel.fingerprintMessage !== ""
|
|
width: parent.width
|
|
horizontalAlignment: Text.AlignHCenter
|
|
text: screen.panel.fingerprintMessage
|
|
color: screen.panel.fingerprintScanning ? Color.accent : screen.panel.dim
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.font.bodySmall
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
|
|
// Offered when fingerprint unlock is on but nothing is stored yet
|
|
Text {
|
|
textFormat: Text.PlainText
|
|
visible: screen.panel.fingerprintUnlock && screen.panel.fingerprintAvailable && !screen.panel.fingerprintStored
|
|
width: parent.width
|
|
horizontalAlignment: Text.AlignHCenter
|
|
text: " Unlock once with your master password to enable fingerprint unlock."
|
|
color: screen.panel.dim
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.font.caption
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
|
|
// Checking / keys loading into helper indicator
|
|
Rectangle {
|
|
visible: screen.panel.status === "checking"
|
|
|| (screen.panel.status === "unlocked" && screen.panel.sshAgentLoadActive)
|
|
width: parent.width
|
|
height: loadingText.implicitHeight + Style.space(20)
|
|
radius: Style.cornerRadius
|
|
color: Util.alpha(Color.popups.text, 0.06)
|
|
|
|
Text {
|
|
id: loadingText
|
|
textFormat: Text.PlainText
|
|
anchors.centerIn: parent
|
|
width: parent.width - Style.space(24)
|
|
text: screen.panel.status === "checking"
|
|
? "Checking vault status..."
|
|
: Model.sshAgentLoadingNote()
|
|
color: screen.panel.fg
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.font.bodySmall
|
|
wrapMode: Text.WordWrap
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
}
|
|
|
|
// PIN entry, offered above the password field when one is set
|
|
Column {
|
|
visible: screen.panel.status === "locked" && screen.panel.pinReady
|
|
width: parent.width
|
|
spacing: Style.space(8)
|
|
|
|
Text {
|
|
textFormat: Text.PlainText
|
|
text: "PIN"
|
|
color: screen.panel.dim
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.font.caption
|
|
font.bold: true
|
|
}
|
|
|
|
Row {
|
|
width: parent.width
|
|
spacing: Style.space(8)
|
|
|
|
TextField {
|
|
id: pinField
|
|
width: parent.width - pinUnlockBtn.width - Style.space(8)
|
|
placeholderText: "Enter your PIN..."
|
|
password: true
|
|
text: screen.panel.pinEntry
|
|
onTextChanged: screen.panel.pinEntry = text.replace(/[^0-9]/g, "")
|
|
onAccepted: screen.panel.submitPinUnlock()
|
|
enabled: !screen.panel.pinBusy && !screen.panel.isUnlocking
|
|
}
|
|
|
|
Button {
|
|
id: pinUnlockBtn
|
|
text: screen.panel.pinBusy ? "Checking..." : "Unlock"
|
|
iconText: screen.panel.pinBusy ? "" : ""
|
|
iconSpinning: screen.panel.pinBusy
|
|
selected: true
|
|
accent: Color.accent
|
|
fontFamily: screen.panel.fontFamily
|
|
focusable: true
|
|
enabled: !screen.panel.pinBusy && !screen.panel.isUnlocking
|
|
onClicked: screen.panel.submitPinUnlock()
|
|
}
|
|
}
|
|
|
|
Text {
|
|
textFormat: Text.PlainText
|
|
visible: screen.panel.pinError !== ""
|
|
width: parent.width
|
|
text: screen.panel.pinError
|
|
color: screen.panel.urgent
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.font.bodySmall
|
|
wrapMode: Text.WordWrap
|
|
}
|
|
|
|
Text {
|
|
textFormat: Text.PlainText
|
|
text: "or use your master password below"
|
|
color: screen.panel.dim
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.font.caption
|
|
}
|
|
}
|
|
|
|
// Fingerprint / Password column matching Panel.qml
|
|
Column {
|
|
visible: screen.panel.status === "locked"
|
|
width: parent.width
|
|
spacing: Style.space(10)
|
|
|
|
Button {
|
|
visible: screen.panel.fingerprintReady
|
|
width: parent.width
|
|
text: screen.panel.fingerprintScanning ? "Waiting for fingerprint..." : "Unlock with Fingerprint"
|
|
iconText: ""
|
|
selected: true
|
|
accent: Color.accent
|
|
fontFamily: screen.panel.fontFamily
|
|
focusable: true
|
|
enabled: !screen.panel.isUnlocking && !screen.panel.fingerprintScanning
|
|
onClicked: screen.panel.startFingerprintUnlock()
|
|
}
|
|
|
|
Row {
|
|
width: parent.width
|
|
spacing: Style.space(8)
|
|
|
|
TextField {
|
|
id: passwordField
|
|
width: parent.width - eyeBtnUnlock.width - Style.space(8)
|
|
placeholderText: "Master password..."
|
|
password: !eyeBtnUnlock.revealed
|
|
text: screen.panel.masterPassword
|
|
onTextChanged: screen.panel.masterPassword = text
|
|
onActiveFocusChanged: if (activeFocus) screen.panel.prepareUnlock()
|
|
onAccepted: screen.panel.unlockVault()
|
|
enabled: !screen.panel.isUnlocking
|
|
}
|
|
|
|
Button {
|
|
id: eyeBtnUnlock
|
|
property bool revealed: false
|
|
iconText: revealed ? "" : ""
|
|
tooltipText: revealed ? "Hide password" : "Show password"
|
|
fontFamily: screen.panel.fontFamily
|
|
focusable: true
|
|
onClicked: revealed = !revealed
|
|
}
|
|
}
|
|
|
|
Button {
|
|
width: parent.width
|
|
text: screen.panel.isUnlocking ? "Unlocking..." : "Unlock Vault"
|
|
iconText: screen.panel.isUnlocking ? "" : ""
|
|
iconSpinning: screen.panel.isUnlocking
|
|
selected: true
|
|
accent: Color.accent
|
|
fontFamily: screen.panel.fontFamily
|
|
focusable: true
|
|
enabled: !screen.panel.isUnlocking
|
|
onClicked: screen.panel.unlockVault()
|
|
}
|
|
}
|
|
|
|
UnlockCaption {
|
|
visible: screen.panel.errorMessage !== ""
|
|
text: screen.panel.errorMessage
|
|
color: screen.panel.urgent
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
|
|
UnlockCaption {
|
|
visible: screen.panel.status === "unauthenticated"
|
|
text: "Sign in from the Bitwarden panel before using vault SSH keys."
|
|
color: screen.panel.urgent
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
|
|
Row {
|
|
width: parent.width
|
|
spacing: Style.space(8)
|
|
|
|
Button {
|
|
text: "Not now (Esc)"
|
|
iconText: ""
|
|
fontFamily: screen.panel.fontFamily
|
|
fontSize: Style.font.bodySmall
|
|
focusable: true
|
|
onClicked: screen.panel.denySshRequest()
|
|
}
|
|
|
|
Button {
|
|
visible: screen.panel.sshUnlockPendingCount > 1
|
|
text: "Deny all (" + screen.panel.sshUnlockPendingCount + ")"
|
|
iconText: ""
|
|
fontFamily: screen.panel.fontFamily
|
|
fontSize: Style.font.bodySmall
|
|
focusable: true
|
|
onClicked: screen.panel.denyAllSshRequests()
|
|
}
|
|
|
|
Item { width: Math.max(0, parent.width - Style.space(screen.panel.sshUnlockPendingCount > 1 ? 280 : 160)); height: 1 }
|
|
|
|
Text {
|
|
textFormat: Text.PlainText
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: screen.panel.sshPromptRemainingSec + "s left"
|
|
color: screen.panel.sshPromptRemainingSec <= 5
|
|
? screen.panel.urgent : screen.panel.dim
|
|
font.family: screen.panel.fontFamily
|
|
font.pixelSize: Style.font.caption
|
|
}
|
|
}
|
|
}
|