From c60cd3a34170e15c37e7472dc7d05b561d0d11bd Mon Sep 17 00:00:00 2001 From: bbedward Date: Fri, 9 Jan 2026 22:19:50 -0500 Subject: [PATCH] modals/auth: add show password option fixes #1311 --- quickshell/Modals/PolkitAuthModal.qml | 125 ++++++++++-------------- quickshell/Modals/WifiPasswordModal.qml | 108 ++++++-------------- quickshell/Widgets/DankTextField.qml | 84 +++++++++++----- 3 files changed, 144 insertions(+), 173 deletions(-) diff --git a/quickshell/Modals/PolkitAuthModal.qml b/quickshell/Modals/PolkitAuthModal.qml index 16c75049..49af0d2b 100644 --- a/quickshell/Modals/PolkitAuthModal.qml +++ b/quickshell/Modals/PolkitAuthModal.qml @@ -11,7 +11,6 @@ FloatingWindow { property var currentFlow: PolkitService.agent?.flow property bool isLoading: false readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2 - property int calculatedHeight: Math.max(240, headerRow.implicitHeight + mainColumn.implicitHeight + Theme.spacingM * 3) function focusPasswordField() { passwordField.forceActiveFocus(); @@ -37,15 +36,19 @@ FloatingWindow { } function cancelAuth() { - if (!currentFlow || isLoading) + if (isLoading) return; - currentFlow.cancelAuthenticationRequest(); + if (currentFlow) { + currentFlow.cancelAuthenticationRequest(); + return; + } + hide(); } objectName: "polkitAuthModal" title: I18n.tr("Authentication") - minimumSize: Qt.size(420, calculatedHeight) - maximumSize: Qt.size(420, calculatedHeight) + minimumSize: Qt.size(460, 220) + maximumSize: Qt.size(460, 220) color: Theme.surfaceContainer visible: false @@ -108,29 +111,24 @@ FloatingWindow { event.accepted = true; } - MouseArea { - anchors.left: parent.left - anchors.right: parent.right - anchors.top: parent.top - height: headerRow.height + Theme.spacingM - onPressed: windowControls.tryStartMove() - onDoubleClicked: windowControls.tryToggleMaximize() - } - Item { - id: headerRow + id: headerSection anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingM - height: Math.max(titleColumn.height, buttonRow.height) + anchors.margins: Theme.spacingM + height: Math.max(titleColumn.implicitHeight, windowButtonRow.implicitHeight) + + MouseArea { + anchors.fill: parent + onPressed: windowControls.tryStartMove() + onDoubleClicked: windowControls.tryToggleMaximize() + } Column { id: titleColumn anchors.left: parent.left - anchors.right: buttonRow.left + anchors.right: windowButtonRow.left anchors.rightMargin: Theme.spacingM spacing: Theme.spacingXS @@ -141,33 +139,34 @@ FloatingWindow { font.weight: Font.Medium } - Column { + StyledText { + text: currentFlow?.message ?? "" + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceTextMedium width: parent.width - spacing: Theme.spacingXS + wrapMode: Text.Wrap + maximumLineCount: 2 + elide: Text.ElideRight + visible: text !== "" + } - StyledText { - text: currentFlow?.message ?? "" - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceTextMedium - width: parent.width - wrapMode: Text.Wrap - } - - StyledText { - visible: (currentFlow?.supplementaryMessage ?? "") !== "" - text: currentFlow?.supplementaryMessage ?? "" - font.pixelSize: Theme.fontSizeSmall - color: (currentFlow?.supplementaryIsError ?? false) ? Theme.error : Theme.surfaceTextMedium - width: parent.width - wrapMode: Text.Wrap - opacity: (currentFlow?.supplementaryIsError ?? false) ? 1 : 0.8 - } + StyledText { + text: currentFlow?.supplementaryMessage ?? "" + font.pixelSize: Theme.fontSizeSmall + color: (currentFlow?.supplementaryIsError ?? false) ? Theme.error : Theme.surfaceTextMedium + width: parent.width + wrapMode: Text.Wrap + maximumLineCount: 2 + elide: Text.ElideRight + opacity: (currentFlow?.supplementaryIsError ?? false) ? 1 : 0.8 + visible: text !== "" } } Row { - id: buttonRow + id: windowButtonRow anchors.right: parent.right + anchors.top: parent.top spacing: Theme.spacingXS DankActionButton { @@ -190,21 +189,19 @@ FloatingWindow { } Column { - id: mainColumn + id: bottomSection anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.bottomMargin: Theme.spacingM - spacing: Theme.spacingM + anchors.margins: Theme.spacingM + spacing: Theme.spacingS StyledText { text: currentFlow?.inputPrompt ?? "" font.pixelSize: Theme.fontSizeMedium color: Theme.surfaceText width: parent.width - visible: (currentFlow?.inputPrompt ?? "") !== "" + visible: text !== "" } Rectangle { @@ -229,7 +226,8 @@ FloatingWindow { font.pixelSize: Theme.fontSizeMedium textColor: Theme.surfaceText text: passwordInput - echoMode: (currentFlow?.responseVisible ?? false) ? TextInput.Normal : TextInput.Password + showPasswordToggle: !(currentFlow?.responseVisible ?? false) + echoMode: (currentFlow?.responseVisible ?? false) || passwordVisible ? TextInput.Normal : TextInput.Password placeholderText: "" backgroundColor: "transparent" enabled: !isLoading @@ -238,38 +236,17 @@ FloatingWindow { } } - Item { + StyledText { + text: I18n.tr("Authentication failed, please try again") + font.pixelSize: Theme.fontSizeSmall + color: Theme.error width: parent.width - height: (currentFlow?.failed ?? false) ? failedText.implicitHeight : 0 - visible: height > 0 - - StyledText { - id: failedText - text: I18n.tr("Authentication failed, please try again") - font.pixelSize: Theme.fontSizeSmall - color: Theme.error - width: parent.width - opacity: (currentFlow?.failed ?? false) ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } - } - - Behavior on height { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Theme.standardEasing - } - } + visible: currentFlow?.failed ?? false } Item { width: parent.width - height: 40 + height: 36 Row { anchors.right: parent.right diff --git a/quickshell/Modals/WifiPasswordModal.qml b/quickshell/Modals/WifiPasswordModal.qml index 19921850..d63c9d20 100644 --- a/quickshell/Modals/WifiPasswordModal.qml +++ b/quickshell/Modals/WifiPasswordModal.qml @@ -33,7 +33,6 @@ FloatingWindow { readonly property bool showPasswordField: fieldsInfo.length === 0 readonly property bool showAnonField: requiresEnterprise && !isVpnPrompt readonly property bool showDomainField: requiresEnterprise && !isVpnPrompt - readonly property bool showShowPasswordCheckbox: fieldsInfo.length === 0 readonly property bool showSavePasswordCheckbox: (isVpnPrompt || fieldsInfo.length > 0) && promptReason !== "pkcs11" readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2 @@ -55,8 +54,6 @@ FloatingWindow { h += inputFieldWithSpacing; if (showDomainField) h += inputFieldWithSpacing; - if (showShowPasswordCheckbox) - h += checkboxRowHeight; if (showSavePasswordCheckbox) h += checkboxRowHeight; return h; @@ -447,7 +444,8 @@ FloatingWindow { anchors.fill: parent font.pixelSize: Theme.fontSizeMedium textColor: Theme.surfaceText - echoMode: modelData.isSecret ? TextInput.Password : TextInput.Normal + showPasswordToggle: modelData.isSecret + echoMode: modelData.isSecret && !passwordVisible ? TextInput.Password : TextInput.Normal placeholderText: getFieldLabel(modelData.name) backgroundColor: "transparent" enabled: root.visible @@ -549,7 +547,8 @@ FloatingWindow { font.pixelSize: Theme.fontSizeMedium textColor: Theme.surfaceText text: wifiPasswordInput - echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password + showPasswordToggle: true + echoMode: passwordVisible ? TextInput.Normal : TextInput.Password placeholderText: (requiresEnterprise && !isVpnPrompt) ? I18n.tr("Password") : "" backgroundColor: "transparent" enabled: root.visible @@ -628,88 +627,43 @@ FloatingWindow { } } - Column { + Row { spacing: Theme.spacingS - width: parent.width + visible: showSavePasswordCheckbox - Row { - spacing: Theme.spacingS - visible: showShowPasswordCheckbox + Rectangle { + id: savePasswordCheckbox - Rectangle { - id: showPasswordCheckbox + property bool checked: true - property bool checked: false + width: 20 + height: 20 + radius: 4 + color: checked ? Theme.primary : "transparent" + border.color: checked ? Theme.primary : Theme.outlineButton + border.width: 2 - width: 20 - height: 20 - radius: 4 - color: checked ? Theme.primary : "transparent" - border.color: checked ? Theme.primary : Theme.outlineButton - border.width: 2 - - DankIcon { - anchors.centerIn: parent - name: "check" - size: 12 - color: Theme.background - visible: parent.checked - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: showPasswordCheckbox.checked = !showPasswordCheckbox.checked - } + DankIcon { + anchors.centerIn: parent + name: "check" + size: 12 + color: Theme.background + visible: parent.checked } - StyledText { - text: I18n.tr("Show password") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: savePasswordCheckbox.checked = !savePasswordCheckbox.checked } } - Row { - spacing: Theme.spacingS - visible: showSavePasswordCheckbox - - Rectangle { - id: savePasswordCheckbox - - property bool checked: false - - width: 20 - height: 20 - radius: 4 - color: checked ? Theme.primary : "transparent" - border.color: checked ? Theme.primary : Theme.outlineButton - border.width: 2 - - DankIcon { - anchors.centerIn: parent - name: "check" - size: 12 - color: Theme.background - visible: parent.checked - } - - MouseArea { - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: savePasswordCheckbox.checked = !savePasswordCheckbox.checked - } - } - - StyledText { - text: I18n.tr("Save password") - font.pixelSize: Theme.fontSizeMedium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } + StyledText { + text: I18n.tr("Save password") + font.pixelSize: Theme.fontSizeMedium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter } } diff --git a/quickshell/Widgets/DankTextField.qml b/quickshell/Widgets/DankTextField.qml index a801e6e1..e1bee6aa 100644 --- a/quickshell/Widgets/DankTextField.qml +++ b/quickshell/Widgets/DankTextField.qml @@ -32,6 +32,8 @@ StyledRect { property color leftIconColor: Theme.surfaceVariantText property color leftIconFocusedColor: Theme.primary property bool showClearButton: false + property bool showPasswordToggle: false + property bool passwordVisible: false property color backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) property color focusedBorderColor: Theme.primary property color normalBorderColor: Theme.outlineMedium @@ -40,7 +42,14 @@ StyledRect { property int focusedBorderWidth: 2 property real cornerRadius: Theme.cornerRadius readonly property real leftPadding: Theme.spacingM + (leftIconName ? leftIconSize + Theme.spacingM : 0) - readonly property real rightPadding: Theme.spacingM + (showClearButton && text.length > 0 ? 24 + Theme.spacingM : 0) + readonly property real rightPadding: { + let p = Theme.spacingM; + if (showPasswordToggle) + p += 24 + Theme.spacingS; + if (showClearButton && text.length > 0) + p += 24 + Theme.spacingS; + return p; + } property real topPadding: Theme.spacingM property real bottomPadding: Theme.spacingM property bool ignoreLeftRightKeys: false @@ -97,8 +106,8 @@ StyledRect { anchors.left: leftIcon.visible ? leftIcon.right : parent.left anchors.leftMargin: Theme.spacingM - anchors.right: clearButton.visible ? clearButton.left : parent.right - anchors.rightMargin: Theme.spacingM + anchors.right: rightButtonsRow.left + anchors.rightMargin: rightButtonsRow.visible ? Theme.spacingS : Theme.spacingM anchors.top: parent.top anchors.topMargin: root.topPadding anchors.bottom: parent.bottom @@ -151,33 +160,64 @@ StyledRect { } } - StyledRect { - id: clearButton + Row { + id: rightButtonsRow - width: 24 - height: 24 - radius: 12 - color: clearArea.containsMouse ? Theme.outlineStrong : "transparent" anchors.right: parent.right anchors.rightMargin: Theme.spacingM anchors.verticalCenter: parent.verticalCenter - visible: showClearButton && text.length > 0 + spacing: Theme.spacingXS + visible: showPasswordToggle || (showClearButton && text.length > 0) - DankIcon { - anchors.centerIn: parent - name: "close" - size: 16 - color: clearArea.containsMouse ? Theme.outline : Theme.surfaceVariantText + StyledRect { + id: passwordToggleButton + + width: 24 + height: 24 + radius: 12 + color: passwordToggleArea.containsMouse ? Theme.outlineStrong : "transparent" + visible: showPasswordToggle + + DankIcon { + anchors.centerIn: parent + name: passwordVisible ? "visibility_off" : "visibility" + size: 16 + color: passwordToggleArea.containsMouse ? Theme.outline : Theme.surfaceVariantText + } + + MouseArea { + id: passwordToggleArea + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: passwordVisible = !passwordVisible + } } - MouseArea { - id: clearArea + StyledRect { + id: clearButton - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: { - textInput.text = ""; + width: 24 + height: 24 + radius: 12 + color: clearArea.containsMouse ? Theme.outlineStrong : "transparent" + visible: showClearButton && text.length > 0 + + DankIcon { + anchors.centerIn: parent + name: "close" + size: 16 + color: clearArea.containsMouse ? Theme.outline : Theme.surfaceVariantText + } + + MouseArea { + id: clearArea + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: textInput.text = "" } } }