1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-11 23:09:42 -04:00

quickshell: drop support for 0.2, require 0.3+

- Remove all compat code
- Rewire LegacyNetworkService to use Quickshell.Networking
- Add parentWindow to settings child windows
This commit is contained in:
bbedward
2026-05-11 13:04:29 -04:00
parent 3989c7f801
commit b8f4c350a8
52 changed files with 1472 additions and 2064 deletions

View File

@@ -67,7 +67,7 @@ FloatingWindow {
spacing: Theme.spacingXS
DankActionButton {
visible: windowControls.supported && windowControls.canMaximize
visible: windowControls.canMaximize
iconName: root.maximized ? "fullscreen_exit" : "fullscreen"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText

View File

@@ -16,6 +16,7 @@ FloatingWindow {
property bool saveMode: false
property string defaultFileName: ""
property var parentModal: null
parentWindow: parentModal
property bool shouldHaveFocus: visible
property bool allowFocusOverride: false
property bool shouldBeVisible: visible

View File

@@ -215,7 +215,7 @@ FloatingWindow {
spacing: Theme.spacingXS
DankActionButton {
visible: windowControls.supported && windowControls.canMaximize
visible: windowControls.canMaximize
iconName: root.maximized ? "fullscreen_exit" : "fullscreen"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText

View File

@@ -0,0 +1,378 @@
import QtQuick
import Quickshell.Io
import qs.Common
import qs.Services
import qs.Widgets
FocusScope {
id: root
property var currentFlow: PolkitService.agent?.flow
property string passwordInput: ""
property bool isLoading: false
property bool awaitingFprintForPassword: false
property var windowControls: null
readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2
property string polkitEtcPamText: ""
property string polkitLibPamText: ""
property string systemAuthPamText: ""
property string commonAuthPamText: ""
property string passwordAuthPamText: ""
readonly property bool polkitPamHasFprint: {
const polkitText = polkitEtcPamText !== "" ? polkitEtcPamText : polkitLibPamText;
if (!polkitText)
return false;
return pamModuleEnabled(polkitText, "pam_fprintd") || (polkitText.includes("system-auth") && pamModuleEnabled(systemAuthPamText, "pam_fprintd")) || (polkitText.includes("common-auth") && pamModuleEnabled(commonAuthPamText, "pam_fprintd")) || (polkitText.includes("password-auth") && pamModuleEnabled(passwordAuthPamText, "pam_fprintd"));
}
signal closeRequested
signal authenticationSucceeded
focus: true
Keys.onEscapePressed: event => {
cancelAuth();
event.accepted = true;
}
function stripPamComment(line) {
if (!line)
return "";
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#"))
return "";
const hashIdx = trimmed.indexOf("#");
if (hashIdx >= 0)
return trimmed.substring(0, hashIdx).trim();
return trimmed;
}
function pamModuleEnabled(pamText, moduleName) {
if (!pamText || !moduleName)
return false;
const lines = pamText.split(/\r?\n/);
for (let i = 0; i < lines.length; i++) {
const line = stripPamComment(lines[i]);
if (line && line.includes(moduleName))
return true;
}
return false;
}
function focusPasswordField() {
passwordField.forceActiveFocus();
}
function reset() {
passwordInput = "";
isLoading = false;
awaitingFprintForPassword = false;
}
function _commitSubmit() {
isLoading = true;
awaitingFprintForPassword = false;
currentFlow.submit(passwordInput);
passwordInput = "";
}
function submitAuth() {
if (!currentFlow || isLoading)
return;
if (!currentFlow.isResponseRequired) {
awaitingFprintForPassword = true;
return;
}
_commitSubmit();
}
function cancelAuth() {
if (isLoading)
return;
awaitingFprintForPassword = false;
if (currentFlow) {
currentFlow.cancelAuthenticationRequest();
return;
}
closeRequested();
}
Connections {
target: root.currentFlow
enabled: root.currentFlow !== null
function onIsResponseRequiredChanged() {
if (!root.currentFlow.isResponseRequired)
return;
if (root.awaitingFprintForPassword && root.passwordInput !== "") {
root._commitSubmit();
return;
}
root.awaitingFprintForPassword = false;
root.isLoading = false;
root.passwordInput = "";
passwordField.forceActiveFocus();
}
function onAuthenticationSucceeded() {
root.authenticationSucceeded();
root.closeRequested();
}
function onAuthenticationFailed() {
root.isLoading = false;
}
function onAuthenticationRequestCancelled() {
root.closeRequested();
}
}
FileView {
path: "/etc/pam.d/polkit-1"
printErrors: false
onLoaded: root.polkitEtcPamText = text()
onLoadFailed: root.polkitEtcPamText = ""
}
FileView {
path: "/usr/lib/pam.d/polkit-1"
printErrors: false
onLoaded: root.polkitLibPamText = text()
onLoadFailed: root.polkitLibPamText = ""
}
FileView {
path: "/etc/pam.d/system-auth"
printErrors: false
onLoaded: root.systemAuthPamText = text()
onLoadFailed: root.systemAuthPamText = ""
}
FileView {
path: "/etc/pam.d/common-auth"
printErrors: false
onLoaded: root.commonAuthPamText = text()
onLoadFailed: root.commonAuthPamText = ""
}
FileView {
path: "/etc/pam.d/password-auth"
printErrors: false
onLoaded: root.passwordAuthPamText = text()
onLoadFailed: root.passwordAuthPamText = ""
}
Item {
id: headerSection
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Theme.spacingM
height: Math.max(titleColumn.implicitHeight, windowButtonRow.implicitHeight)
MouseArea {
anchors.fill: parent
enabled: root.windowControls !== null
onPressed: {
if (root.windowControls)
root.windowControls.tryStartMove();
}
onDoubleClicked: {
if (root.windowControls)
root.windowControls.tryToggleMaximize();
}
}
Column {
id: titleColumn
anchors.left: parent.left
anchors.right: windowButtonRow.left
anchors.rightMargin: Theme.spacingM
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Authentication Required")
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: root.currentFlow?.message ?? ""
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium
width: parent.width
wrapMode: Text.Wrap
maximumLineCount: 2
elide: Text.ElideRight
visible: text !== ""
}
StyledText {
text: root.currentFlow?.supplementaryMessage ?? ""
font.pixelSize: Theme.fontSizeSmall
color: (root.currentFlow?.supplementaryIsError ?? false) ? Theme.error : Theme.surfaceTextMedium
width: parent.width
wrapMode: Text.Wrap
maximumLineCount: 2
elide: Text.ElideRight
opacity: (root.currentFlow?.supplementaryIsError ?? false) ? 1 : 0.8
visible: text !== ""
}
}
Row {
id: windowButtonRow
anchors.right: parent.right
anchors.top: parent.top
spacing: Theme.spacingXS
DankActionButton {
visible: root.windowControls?.supported === true && root.windowControls?.canMaximize === true
iconName: (root.windowControls?.targetWindow?.maximized ?? false) ? "fullscreen_exit" : "fullscreen"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: {
if (root.windowControls)
root.windowControls.tryToggleMaximize();
}
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
enabled: !root.isLoading
opacity: enabled ? 1 : 0.5
onClicked: root.cancelAuth()
}
}
}
Column {
id: bottomSection
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: Theme.spacingM
spacing: Theme.spacingS
StyledText {
text: root.currentFlow?.inputPrompt ?? ""
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
width: parent.width
visible: text !== ""
}
DankTextField {
id: passwordField
width: parent.width
height: root.inputFieldHeight
backgroundColor: Theme.surfaceHover
normalBorderColor: Theme.outlineStrong
focusedBorderColor: Theme.primary
borderWidth: 1
focusedBorderWidth: 2
leftIconName: root.polkitPamHasFprint ? "fingerprint" : ""
leftIconSize: 20
leftIconColor: Theme.primary
leftIconFocusedColor: Theme.primary
opacity: root.isLoading ? 0.5 : 1
font.pixelSize: Theme.fontSizeMedium
textColor: Theme.surfaceText
text: root.passwordInput
showPasswordToggle: !(root.currentFlow?.responseVisible ?? false)
echoMode: (root.currentFlow?.responseVisible ?? false) || passwordVisible ? TextInput.Normal : TextInput.Password
placeholderText: ""
enabled: !root.isLoading
onTextEdited: root.passwordInput = text
onAccepted: root.submitAuth()
}
StyledText {
text: I18n.tr("Authentication failed, please try again")
font.pixelSize: Theme.fontSizeSmall
color: Theme.error
width: parent.width
visible: root.currentFlow?.failed ?? false
}
Item {
width: parent.width
height: 36
Row {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
Rectangle {
width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
border.color: Theme.surfaceVariantAlpha
border.width: 1
enabled: !root.isLoading
opacity: enabled ? 1 : 0.5
StyledText {
id: cancelText
anchors.centerIn: parent
text: I18n.tr("Cancel")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
MouseArea {
id: cancelArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
enabled: parent.enabled
onClicked: root.cancelAuth()
}
}
Rectangle {
width: Math.max(80, authText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: authArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
enabled: !root.isLoading
opacity: enabled ? 1 : 0.5
StyledText {
id: authText
anchors.centerIn: parent
text: I18n.tr("Authenticate")
font.pixelSize: Theme.fontSizeMedium
color: Theme.background
font.weight: Font.Medium
}
MouseArea {
id: authArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
enabled: parent.enabled
onClicked: root.submitAuth()
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
}

View File

@@ -1,427 +1,68 @@
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import qs.Common
import qs.Services
import qs.Widgets
PanelWindow {
FloatingWindow {
id: root
property bool disablePopupTransparency: true
property string passwordInput: ""
property var currentFlow: PolkitService.agent?.flow
property bool isLoading: false
property bool awaitingFprintForPassword: false
readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2
property string polkitEtcPamText: ""
property string polkitLibPamText: ""
property string systemAuthPamText: ""
property string commonAuthPamText: ""
property string passwordAuthPamText: ""
readonly property bool polkitPamHasFprint: {
const polkitText = polkitEtcPamText !== "" ? polkitEtcPamText : polkitLibPamText;
if (!polkitText)
return false;
return pamModuleEnabled(polkitText, "pam_fprintd") || (polkitText.includes("system-auth") && pamModuleEnabled(systemAuthPamText, "pam_fprintd")) || (polkitText.includes("common-auth") && pamModuleEnabled(commonAuthPamText, "pam_fprintd")) || (polkitText.includes("password-auth") && pamModuleEnabled(passwordAuthPamText, "pam_fprintd"));
}
function stripPamComment(line) {
if (!line)
return "";
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#"))
return "";
const hashIdx = trimmed.indexOf("#");
if (hashIdx >= 0)
return trimmed.substring(0, hashIdx).trim();
return trimmed;
}
function pamModuleEnabled(pamText, moduleName) {
if (!pamText || !moduleName)
return false;
const lines = pamText.split(/\r?\n/);
for (let i = 0; i < lines.length; i++) {
const line = stripPamComment(lines[i]);
if (line && line.includes(moduleName))
return true;
}
return false;
}
function focusPasswordField() {
passwordField.forceActiveFocus();
}
function show(targetScreen) {
if (targetScreen)
screen = targetScreen;
passwordInput = "";
isLoading = false;
awaitingFprintForPassword = false;
function show() {
if (contentLoader.item)
contentLoader.item.reset();
visible = true;
Qt.callLater(focusPasswordField);
Qt.callLater(focusContent);
}
function hide() {
visible = false;
}
function _commitSubmit() {
isLoading = true;
awaitingFprintForPassword = false;
currentFlow.submit(passwordInput);
passwordInput = "";
}
function submitAuth() {
if (!currentFlow || isLoading)
return;
if (!currentFlow.isResponseRequired) {
awaitingFprintForPassword = true;
return;
}
_commitSubmit();
}
function cancelAuth() {
if (isLoading)
return;
awaitingFprintForPassword = false;
if (currentFlow) {
currentFlow.cancelAuthenticationRequest();
return;
}
hide();
function focusContent() {
if (contentLoader.item)
contentLoader.item.focusPasswordField();
}
objectName: "polkitAuthModal"
screen: Quickshell.screens[0]
color: "transparent"
title: I18n.tr("Authentication")
minimumSize: Qt.size(460, 220)
maximumSize: Qt.size(460, 220)
color: Theme.surfaceContainer
visible: false
WlrLayershell.namespace: "dms:polkit-auth"
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
anchors {
left: true
top: true
right: true
bottom: true
}
onVisibleChanged: {
if (visible) {
Qt.callLater(focusPasswordField);
Qt.callLater(focusContent);
return;
}
passwordInput = "";
isLoading = false;
awaitingFprintForPassword = false;
if (contentLoader.item)
contentLoader.item.reset();
}
Connections {
target: PolkitService.agent
enabled: PolkitService.polkitAvailable
function onAuthenticationRequestStarted() {
show();
}
function onIsActiveChanged() {
if (!(PolkitService.agent?.isActive ?? false))
hide();
root.hide();
}
}
Connections {
target: currentFlow
enabled: currentFlow !== null
function onIsResponseRequiredChanged() {
if (!currentFlow.isResponseRequired)
return;
if (awaitingFprintForPassword && passwordInput !== "") {
_commitSubmit();
return;
}
awaitingFprintForPassword = false;
isLoading = false;
passwordInput = "";
passwordField.forceActiveFocus();
}
function onAuthenticationSucceeded() {
hide();
}
function onAuthenticationFailed() {
isLoading = false;
}
function onAuthenticationRequestCancelled() {
hide();
}
}
FileView {
path: "/etc/pam.d/polkit-1"
printErrors: false
onLoaded: root.polkitEtcPamText = text()
onLoadFailed: root.polkitEtcPamText = ""
}
FileView {
path: "/usr/lib/pam.d/polkit-1"
printErrors: false
onLoaded: root.polkitLibPamText = text()
onLoadFailed: root.polkitLibPamText = ""
}
FileView {
path: "/etc/pam.d/system-auth"
printErrors: false
onLoaded: root.systemAuthPamText = text()
onLoadFailed: root.systemAuthPamText = ""
}
FileView {
path: "/etc/pam.d/common-auth"
printErrors: false
onLoaded: root.commonAuthPamText = text()
onLoadFailed: root.commonAuthPamText = ""
}
FileView {
path: "/etc/pam.d/password-auth"
printErrors: false
onLoaded: root.passwordAuthPamText = text()
onLoadFailed: root.passwordAuthPamText = ""
}
// Dim overlay — clicking outside cancels authentication
Rectangle {
Loader {
id: contentLoader
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.45)
MouseArea {
anchors.fill: parent
onClicked: cancelAuth()
active: root.visible
sourceComponent: PolkitAuthContent {
windowControls: windowControls
onCloseRequested: root.hide()
}
}
// Centered dialog box
Rectangle {
id: dialogBox
width: 460
height: 220
anchors.centerIn: parent
color: Theme.surfaceContainer
radius: Theme.cornerRadius
FocusScope {
id: contentFocusScope
anchors.fill: parent
focus: true
Keys.onEscapePressed: event => {
cancelAuth();
event.accepted = true;
}
Item {
id: headerSection
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Theme.spacingM
height: Math.max(titleColumn.implicitHeight, windowButtonRow.implicitHeight)
Column {
id: titleColumn
anchors.left: parent.left
anchors.right: windowButtonRow.left
anchors.rightMargin: Theme.spacingM
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Authentication Required")
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: currentFlow?.message ?? ""
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium
width: parent.width
wrapMode: Text.Wrap
maximumLineCount: 2
elide: Text.ElideRight
visible: text !== ""
}
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: windowButtonRow
anchors.right: parent.right
anchors.top: parent.top
spacing: Theme.spacingXS
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
enabled: !isLoading
opacity: enabled ? 1 : 0.5
onClicked: cancelAuth()
}
}
}
Column {
id: bottomSection
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: Theme.spacingM
spacing: Theme.spacingS
StyledText {
text: currentFlow?.inputPrompt ?? ""
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
width: parent.width
visible: text !== ""
}
DankTextField {
id: passwordField
width: parent.width
height: inputFieldHeight
backgroundColor: Theme.surfaceHover
normalBorderColor: Theme.outlineStrong
focusedBorderColor: Theme.primary
borderWidth: 1
focusedBorderWidth: 2
leftIconName: polkitPamHasFprint ? "fingerprint" : ""
leftIconSize: 20
leftIconColor: Theme.primary
leftIconFocusedColor: Theme.primary
opacity: isLoading ? 0.5 : 1
font.pixelSize: Theme.fontSizeMedium
textColor: Theme.surfaceText
text: passwordInput
showPasswordToggle: !(currentFlow?.responseVisible ?? false)
echoMode: (currentFlow?.responseVisible ?? false) || passwordVisible ? TextInput.Normal : TextInput.Password
placeholderText: ""
enabled: !isLoading
onTextEdited: passwordInput = text
onAccepted: submitAuth()
}
StyledText {
text: I18n.tr("Authentication failed, please try again")
font.pixelSize: Theme.fontSizeSmall
color: Theme.error
width: parent.width
visible: currentFlow?.failed ?? false
}
Item {
width: parent.width
height: 36
Row {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
Rectangle {
width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
border.color: Theme.surfaceVariantAlpha
border.width: 1
enabled: !isLoading
opacity: enabled ? 1 : 0.5
StyledText {
id: cancelText
anchors.centerIn: parent
text: I18n.tr("Cancel")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
MouseArea {
id: cancelArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
enabled: parent.enabled
onClicked: cancelAuth()
}
}
Rectangle {
width: Math.max(80, authText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: authArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
enabled: !isLoading
opacity: enabled ? 1 : 0.5
StyledText {
id: authText
anchors.centerIn: parent
text: I18n.tr("Authenticate")
font.pixelSize: Theme.fontSizeMedium
color: Theme.background
font.weight: Font.Medium
}
MouseArea {
id: authArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
enabled: parent.enabled
onClicked: submitAuth()
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
}
FloatingWindowControls {
id: windowControls
targetWindow: root
}
}

View File

@@ -0,0 +1,51 @@
import QtQuick
import Quickshell.Wayland
import qs.Common
import qs.Modals.Common
import qs.Services
DankModal {
id: root
property var parentPopout: null
layerNamespace: "dms:polkit-auth-surface"
modalWidth: 460
modalHeight: 220
backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
closeOnEscapeKey: true
closeOnBackgroundClick: false
allowStacking: true
keepPopoutsOpen: true
onOpened: {
if (parentPopout)
parentPopout.customKeyboardFocus = WlrKeyboardFocus.None;
Qt.callLater(() => {
if (contentLoader.item) {
contentLoader.item.reset();
contentLoader.item.focusPasswordField();
}
});
}
onDialogClosed: {
if (parentPopout)
parentPopout.customKeyboardFocus = null;
}
Connections {
target: PolkitService.agent
enabled: PolkitService.polkitAvailable
function onIsActiveChanged() {
if (!(PolkitService.agent?.isActive ?? false))
root.close();
}
}
content: PolkitAuthContent {
focus: true
onCloseRequested: root.close()
}
}

View File

@@ -274,7 +274,7 @@ FloatingWindow {
spacing: Theme.spacingXS
DankActionButton {
visible: windowControls.supported
visible: windowControls.canMaximize
circular: false
iconName: processListModal.maximized ? "fullscreen_exit" : "fullscreen"
iconSize: Theme.iconSize - 4

View File

@@ -235,7 +235,7 @@ FloatingWindow {
spacing: Theme.spacingXS
DankActionButton {
visible: windowControls.supported
visible: windowControls.canMaximize
circular: false
iconName: settingsModal.maximized ? "fullscreen_exit" : "fullscreen"
iconSize: Theme.iconSize - 4

View File

@@ -381,7 +381,7 @@ FloatingWindow {
spacing: Theme.spacingXS
DankActionButton {
visible: windowControls.supported && windowControls.canMaximize
visible: windowControls.canMaximize
iconName: root.maximized ? "fullscreen_exit" : "fullscreen"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText

View File

@@ -1,6 +1,5 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Services
import qs.Widgets
@@ -97,7 +96,7 @@ FloatingWindow {
spacing: Theme.spacingXS
DankActionButton {
visible: windowControls.supported && windowControls.canMaximize
visible: windowControls.canMaximize
iconName: root.maximized ? "fullscreen_exit" : "fullscreen"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
@@ -213,5 +212,4 @@ FloatingWindow {
id: windowControls
targetWindow: root
}
}