151 lines
4.9 KiB
QML
Raw Normal View History

2026-07-24 00:24:03 -03:00
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Logos.Theme
import Logos.Controls
import "../controls"
Popup {
id: root
// Context set by the parent right before open(). Only ever opened for an
// unlabeled account — the wallet core has no way to rename or remove a label
// once added, so there's no "current label" to prefill or compare against.
property string accountId: ""
property bool isPublic: true
// Debounced availability-check result. The parent owns the backend connection,
// so it drives these two properties in response to checkAvailabilityRequested.
property bool checkingAvailability: false
property bool labelAvailable: true
// Save round-trip state, likewise driven by the parent: saving stays true and the
// popup stays open until the parent reports success (closeOnSaveSuccess) or failure
// (reportSaveError) — so a failed save isn't silently swallowed by an immediate close.
property bool saving: false
property string saveError: ""
signal checkAvailabilityRequested(string label)
signal saveRequested(string accountId, bool isPublic, string label)
function closeOnSaveSuccess() {
root.saving = false
root.close()
}
function reportSaveError(message) {
root.saving = false
root.saveError = message
}
readonly property string trimmedText: labelField.text.trim()
readonly property bool saveEnabled: trimmedText.length > 0
&& root.labelAvailable && !root.checkingAvailability
modal: true
dim: true
padding: Theme.spacing.large
// No dismissal while a save is in flight — mirrors the disabled Cancel/Save
// buttons below, so a stale response can't land on a dialog the user thinks
// they already closed.
closePolicy: root.saving ? Popup.NoAutoClose : (Popup.CloseOnEscape | Popup.CloseOnPressOutside)
anchors.centerIn: parent
background: Rectangle {
color: Theme.palette.backgroundSecondary
radius: Theme.spacing.radiusXlarge
border.color: Theme.palette.backgroundElevated
}
onOpened: {
labelField.text = ""
root.labelAvailable = true
root.checkingAvailability = false
root.saving = false
root.saveError = ""
labelField.forceActiveFocus()
labelField.selectAll()
}
Timer {
id: debounce
interval: 400
onTriggered: {
if (root.trimmedText.length > 0) {
root.checkingAvailability = true
root.checkAvailabilityRequested(root.trimmedText)
} else {
root.checkingAvailability = false
}
}
}
contentItem: ColumnLayout {
width: 320
spacing: Theme.spacing.large
LogosText {
text: qsTr("Add label")
font.pixelSize: Theme.typography.titleText
font.weight: Theme.typography.weightBold
color: Theme.palette.text
}
LogosTextField {
id: labelField
Layout.fillWidth: true
enabled: !root.saving
onTextChanged: {
root.saveError = ""
// Mark as checking immediately so saveEnabled can't go true on stale
// (or no) availability data during the debounce window — the Timer
// below only confirms/updates the result once typing settles.
root.checkingAvailability = root.trimmedText.length > 0
debounce.restart()
}
}
LogosText {
Layout.fillWidth: true
wrapMode: Text.WordWrap
font.pixelSize: Theme.typography.secondaryText
color: Theme.palette.error
visible: root.trimmedText.length > 0 && !root.checkingAvailability && !root.labelAvailable
text: qsTr("That label is already in use.")
}
LogosText {
Layout.fillWidth: true
wrapMode: Text.WordWrap
font.pixelSize: Theme.typography.secondaryText
color: Theme.palette.error
visible: root.saveError.length > 0
text: root.saveError
}
RowLayout {
Layout.topMargin: Theme.spacing.medium
spacing: Theme.spacing.medium
Layout.fillWidth: true
Item { Layout.fillWidth: true }
FeedbackButton {
text: qsTr("Cancel")
enabled: !root.saving
onClicked: root.close()
}
FeedbackButton {
text: root.saving ? qsTr("Saving…") : qsTr("Save")
enabled: root.saveEnabled && !root.saving
onClicked: {
root.saving = true
root.saveError = ""
root.saveRequested(root.accountId, root.isPublic, root.trimmedText)
}
}
}
}
}