mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
Merge branch 'master' of github.com:bbedward/DankMaterialShell into wip/plugins
This commit is contained in:
@@ -127,6 +127,44 @@ DankPopout {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectNext()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectPrevious()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectNext()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectPrevious()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
|
||||
if (appLauncher.viewMode === "grid") {
|
||||
if (event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectNextInRow()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_H && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectPreviousInRow()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!searchField.activeFocus && event.text && /[a-zA-Z0-9\s]/.test(event.text)) {
|
||||
searchField.forceActiveFocus()
|
||||
searchField.insertText(event.text)
|
||||
|
||||
@@ -47,7 +47,6 @@ PanelWindow {
|
||||
border.width: 0
|
||||
opacity: powerMenuVisible ? 1 : 0
|
||||
scale: powerMenuVisible ? 1 : 0.85
|
||||
antialiasing: true
|
||||
|
||||
MouseArea {
|
||||
|
||||
|
||||
@@ -338,32 +338,28 @@ Rectangle {
|
||||
|
||||
width: {
|
||||
if (root.isVertical) {
|
||||
// Vertical mode: width is like horizontal height (small and fixed)
|
||||
return SettingsData.showWorkspaceApps ? widgetHeight * 0.8 : widgetHeight * 0.6;
|
||||
return SettingsData.showWorkspaceApps ? widgetHeight * 0.7 : widgetHeight * 0.5;
|
||||
} else {
|
||||
// Horizontal mode - original logic
|
||||
if (SettingsData.showWorkspaceApps && loadedIcons.length > 0) {
|
||||
const numIcons = Math.min(loadedIcons.length, SettingsData.maxWorkspaceIcons);
|
||||
const iconsWidth = numIcons * 18 + (numIcons > 0 ? (numIcons - 1) * Theme.spacingXS : 0);
|
||||
const baseWidth = isActive ? root.widgetHeight * 1.0 + Theme.spacingXS : root.widgetHeight * 0.8;
|
||||
const baseWidth = isActive ? root.widgetHeight * 0.9 + Theme.spacingXS : root.widgetHeight * 0.7;
|
||||
return baseWidth + iconsWidth;
|
||||
}
|
||||
return isActive ? root.widgetHeight * 1.2 : root.widgetHeight * 0.8;
|
||||
return isActive ? root.widgetHeight * 1.05 : root.widgetHeight * 0.7;
|
||||
}
|
||||
}
|
||||
height: {
|
||||
if (root.isVertical) {
|
||||
// Vertical mode: height is like horizontal width (dynamic)
|
||||
if (SettingsData.showWorkspaceApps && loadedIcons.length > 0) {
|
||||
const numIcons = Math.min(loadedIcons.length, SettingsData.maxWorkspaceIcons);
|
||||
const iconsHeight = numIcons * 18 + (numIcons > 0 ? (numIcons - 1) * Theme.spacingXS : 0);
|
||||
const baseHeight = isActive ? root.widgetHeight * 1.0 + Theme.spacingXS : root.widgetHeight * 0.8;
|
||||
const baseHeight = isActive ? root.widgetHeight * 0.9 + Theme.spacingXS : root.widgetHeight * 0.7;
|
||||
return baseHeight + iconsHeight;
|
||||
}
|
||||
return isActive ? root.widgetHeight * 1.2 : root.widgetHeight * 0.8;
|
||||
return isActive ? root.widgetHeight * 1.05 : root.widgetHeight * 0.7;
|
||||
} else {
|
||||
// Horizontal mode - original logic
|
||||
return SettingsData.showWorkspaceApps ? widgetHeight * 0.8 : widgetHeight * 0.6;
|
||||
return SettingsData.showWorkspaceApps ? widgetHeight * 0.7 : widgetHeight * 0.5;
|
||||
}
|
||||
}
|
||||
radius: Math.min(width, height) / 2
|
||||
@@ -388,7 +384,9 @@ Rectangle {
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.centerIn: parent
|
||||
width: root.isVertical ? parent.width + Theme.spacingXL : parent.width
|
||||
height: root.isVerical ? parent.height : parent.height + Theme.spacingXL
|
||||
hoverEnabled: !isPlaceholder
|
||||
cursorShape: isPlaceholder ? Qt.ArrowCursor : Qt.PointingHandCursor
|
||||
enabled: !isPlaceholder
|
||||
|
||||
@@ -63,7 +63,6 @@ DankPopout {
|
||||
implicitHeight: contentColumn.height + Theme.spacingM * 2
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadius
|
||||
antialiasing: true
|
||||
focus: true
|
||||
|
||||
Component.onCompleted: {
|
||||
@@ -94,7 +93,6 @@ DankPopout {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
|
||||
radius: parent.radius
|
||||
antialiasing: true
|
||||
|
||||
SequentialAnimation on opacity {
|
||||
running: root.shouldBeVisible
|
||||
|
||||
@@ -271,7 +271,6 @@ Item {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
antialiasing: true
|
||||
opacity: 1.0
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
@@ -360,7 +359,6 @@ Item {
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6)
|
||||
border.width: 2
|
||||
radius: Theme.cornerRadius * 2
|
||||
antialiasing: true
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: MultiEffect {
|
||||
@@ -433,11 +431,10 @@ Item {
|
||||
delegate: Rectangle {
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
|
||||
width: parent.width
|
||||
height: 48
|
||||
radius: Theme.cornerRadius
|
||||
antialiasing: true
|
||||
color: deviceMouseAreaLeft.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.surfaceContainerHigh
|
||||
border.color: modelData === AudioService.sink ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: modelData === AudioService.sink ? 2 : 1
|
||||
@@ -520,7 +517,6 @@ Item {
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6)
|
||||
border.width: 2
|
||||
radius: Theme.cornerRadius * 2
|
||||
antialiasing: true
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: MultiEffect {
|
||||
@@ -597,7 +593,6 @@ Item {
|
||||
width: parent.width
|
||||
height: 48
|
||||
radius: Theme.cornerRadius
|
||||
antialiasing: true
|
||||
color: playerMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.surfaceContainerHigh
|
||||
border.color: modelData === activePlayer ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: modelData === activePlayer ? 2 : 1
|
||||
@@ -843,7 +838,6 @@ Item {
|
||||
height: 40
|
||||
radius: 20
|
||||
anchors.centerIn: parent
|
||||
antialiasing: true
|
||||
color: shuffleArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
DankIcon {
|
||||
@@ -885,7 +879,6 @@ Item {
|
||||
height: 40
|
||||
radius: 20
|
||||
anchors.centerIn: parent
|
||||
antialiasing: true
|
||||
color: prevBtnArea.containsMouse ? Theme.surfaceContainerHigh : "transparent"
|
||||
|
||||
DankIcon {
|
||||
@@ -925,7 +918,6 @@ Item {
|
||||
height: 50
|
||||
radius: 25
|
||||
anchors.centerIn: parent
|
||||
antialiasing: true
|
||||
color: Theme.primary
|
||||
|
||||
DankIcon {
|
||||
@@ -965,7 +957,6 @@ Item {
|
||||
height: 40
|
||||
radius: 20
|
||||
anchors.centerIn: parent
|
||||
antialiasing: true
|
||||
color: nextBtnArea.containsMouse ? Theme.surfaceContainerHigh : "transparent"
|
||||
|
||||
DankIcon {
|
||||
@@ -996,7 +987,6 @@ Item {
|
||||
height: 40
|
||||
radius: 20
|
||||
anchors.centerIn: parent
|
||||
antialiasing: true
|
||||
color: repeatArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
DankIcon {
|
||||
@@ -1057,7 +1047,6 @@ Item {
|
||||
radius: 20
|
||||
x: parent.width - 40 - Theme.spacingM
|
||||
y: 185
|
||||
antialiasing: true
|
||||
color: playerSelectorArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent"
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
border.width: 1
|
||||
@@ -1111,7 +1100,6 @@ Item {
|
||||
radius: 20
|
||||
x: parent.width - 40 - Theme.spacingM
|
||||
y: 130
|
||||
antialiasing: true
|
||||
color: volumeButtonArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent"
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
border.width: 1
|
||||
@@ -1166,8 +1154,7 @@ Item {
|
||||
height: 40
|
||||
radius: 20
|
||||
x: parent.width - 40 - Theme.spacingM
|
||||
y: 240
|
||||
antialiasing: true
|
||||
y: 240
|
||||
color: audioDevicesArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) : "transparent"
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
border.width: 1
|
||||
@@ -1229,7 +1216,6 @@ Item {
|
||||
|
||||
background: Rectangle {
|
||||
radius: Theme.cornerRadius * 2
|
||||
antialiasing: true
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
border.width: 1
|
||||
@@ -1290,7 +1276,6 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
color: Theme.surfaceContainerHigh
|
||||
radius: Theme.cornerRadius
|
||||
antialiasing: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -1304,7 +1289,6 @@ Item {
|
||||
bottomRightRadius: Theme.cornerRadius
|
||||
topLeftRadius: 0
|
||||
topRightRadius: 0
|
||||
antialiasing: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -1312,7 +1296,6 @@ Item {
|
||||
width: parent.width + 8
|
||||
height: 8
|
||||
radius: Theme.cornerRadius
|
||||
antialiasing: true
|
||||
y: {
|
||||
const ratio = defaultSink ? Math.min(1.0, defaultSink.audio.volume) : 0
|
||||
const travel = parent.height - height
|
||||
@@ -1326,7 +1309,6 @@ Item {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
antialiasing: true
|
||||
color: Theme.onPrimary
|
||||
opacity: volumeSliderArea.pressed ? 0.16 : (volumeSliderArea.containsMouse ? 0.08 : 0)
|
||||
visible: opacity > 0
|
||||
@@ -1338,7 +1320,6 @@ Item {
|
||||
width: 0
|
||||
height: 0
|
||||
radius: width / 2
|
||||
antialiasing: true
|
||||
color: Theme.onPrimary
|
||||
opacity: 0
|
||||
|
||||
|
||||
@@ -13,83 +13,22 @@ Card {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Item {
|
||||
DankCircularImage {
|
||||
id: avatarContainer
|
||||
|
||||
property bool hasImage: profileImageLoader.status === Image.Ready
|
||||
|
||||
|
||||
width: 77
|
||||
height: 77
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 36
|
||||
color: Theme.primary
|
||||
visible: !avatarContainer.hasImage
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: UserInfoService.username.length > 0 ? UserInfoService.username.charAt(0).toUpperCase() : "b"
|
||||
font.pixelSize: Theme.fontSizeXLarge + 4
|
||||
font.weight: Font.Bold
|
||||
color: Theme.background
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: profileImageLoader
|
||||
|
||||
source: {
|
||||
if (PortalService.profileImage === "")
|
||||
return ""
|
||||
|
||||
if (PortalService.profileImage.startsWith("/"))
|
||||
return "file://" + PortalService.profileImage
|
||||
|
||||
return PortalService.profileImage
|
||||
}
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
mipmap: true
|
||||
cache: true
|
||||
visible: false
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
source: profileImageLoader
|
||||
maskEnabled: true
|
||||
maskSource: circularMask
|
||||
visible: avatarContainer.hasImage
|
||||
maskThresholdMin: 0.5
|
||||
maskSpreadAtMin: 1
|
||||
}
|
||||
|
||||
Item {
|
||||
id: circularMask
|
||||
width: 77 - 4
|
||||
height: 77 - 4
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
visible: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: width / 2
|
||||
color: "black"
|
||||
antialiasing: true
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "person"
|
||||
size: Theme.iconSize + 8
|
||||
color: Theme.error
|
||||
visible: PortalService.profileImage !== "" && profileImageLoader.status === Image.Error
|
||||
imageSource: {
|
||||
if (PortalService.profileImage === "")
|
||||
return ""
|
||||
|
||||
if (PortalService.profileImage.startsWith("/"))
|
||||
return "file://" + PortalService.profileImage
|
||||
|
||||
return PortalService.profileImage
|
||||
}
|
||||
fallbackIcon: "person"
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -104,7 +43,7 @@ Card {
|
||||
elide: Text.ElideRight
|
||||
width: parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3
|
||||
}
|
||||
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
@@ -128,7 +67,7 @@ Card {
|
||||
width: parent.parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - 16 - Theme.spacingS
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
@@ -141,7 +80,7 @@ Card {
|
||||
|
||||
StyledText {
|
||||
id: uptimeText
|
||||
|
||||
|
||||
property real availableWidth: parent.parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - 16 - Theme.spacingS
|
||||
property real longTextWidth: {
|
||||
const fontSize = Math.round(Theme.fontSizeSmall || 12)
|
||||
|
||||
@@ -218,7 +218,6 @@ Item {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
|
||||
antialiasing: true
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
@@ -233,7 +232,6 @@ Item {
|
||||
Layout.fillHeight: true
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
antialiasing: true
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
@@ -245,7 +243,6 @@ Item {
|
||||
radius: 16
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
antialiasing: true
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -282,7 +279,6 @@ Item {
|
||||
Layout.fillHeight: true
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
antialiasing: true
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
@@ -294,7 +290,6 @@ Item {
|
||||
radius: 16
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
antialiasing: true
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -331,7 +326,6 @@ Item {
|
||||
Layout.fillHeight: true
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
antialiasing: true
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
@@ -343,7 +337,6 @@ Item {
|
||||
radius: 16
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
antialiasing: true
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -380,7 +373,6 @@ Item {
|
||||
Layout.fillHeight: true
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
antialiasing: true
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
@@ -392,7 +384,6 @@ Item {
|
||||
radius: 16
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
antialiasing: true
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -429,7 +420,6 @@ Item {
|
||||
Layout.fillHeight: true
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
antialiasing: true
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
@@ -441,7 +431,6 @@ Item {
|
||||
radius: 16
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
antialiasing: true
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -478,7 +467,6 @@ Item {
|
||||
Layout.fillHeight: true
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
antialiasing: true
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
@@ -490,7 +478,6 @@ Item {
|
||||
radius: 16
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
antialiasing: true
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -527,7 +514,6 @@ Item {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
|
||||
antialiasing: true
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -554,8 +540,7 @@ Item {
|
||||
width: (parent.width - Theme.spacingXS * 6) / 7
|
||||
height: parent.height
|
||||
radius: Theme.cornerRadius
|
||||
antialiasing: true
|
||||
|
||||
|
||||
property var dayDate: {
|
||||
const date = new Date()
|
||||
date.setDate(date.getDate() + index)
|
||||
|
||||
@@ -20,11 +20,13 @@ Variants {
|
||||
|
||||
WlrLayershell.namespace: "quickshell:dock"
|
||||
|
||||
readonly property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
||||
|
||||
anchors {
|
||||
top: SettingsData.dockPosition === SettingsData.Position.Top
|
||||
bottom: SettingsData.dockPosition === SettingsData.Position.Bottom
|
||||
left: true
|
||||
right: true
|
||||
top: !isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top) : true
|
||||
bottom: !isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom) : true
|
||||
left: !isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Left)
|
||||
right: !isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Right)
|
||||
}
|
||||
|
||||
property var modelData: item
|
||||
@@ -35,12 +37,20 @@ Variants {
|
||||
readonly property real widgetHeight: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
|
||||
readonly property real effectiveBarHeight: Math.max(widgetHeight + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||
readonly property real barSpacing: {
|
||||
// Only add spacing if bar is visible, horizontal (Top/Bottom), and at same position as dock
|
||||
const barIsHorizontal = (SettingsData.dankBarPosition === SettingsData.Position.Top || SettingsData.dankBarPosition === SettingsData.Position.Bottom)
|
||||
const barIsVertical = (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right)
|
||||
const samePosition = (SettingsData.dockPosition === SettingsData.dankBarPosition)
|
||||
return (SettingsData.dankBarVisible && barIsHorizontal && samePosition)
|
||||
? (SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap)
|
||||
: 0
|
||||
const dockIsHorizontal = !isVertical
|
||||
const dockIsVertical = isVertical
|
||||
|
||||
if (!SettingsData.dankBarVisible) return 0
|
||||
if (dockIsHorizontal && barIsHorizontal && samePosition) {
|
||||
return SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap
|
||||
}
|
||||
if (dockIsVertical && barIsVertical && samePosition) {
|
||||
return SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
readonly property real dockMargin: SettingsData.dockSpacing
|
||||
@@ -103,6 +113,83 @@ Variants {
|
||||
item: dockMouseArea
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: appTooltip
|
||||
z: 1000
|
||||
|
||||
property var hoveredButton: {
|
||||
if (!dockApps.children[0]) {
|
||||
return null
|
||||
}
|
||||
const layoutItem = dockApps.children[0]
|
||||
const flowLayout = layoutItem.children[0]
|
||||
let repeater = null
|
||||
for (var i = 0; i < flowLayout.children.length; i++) {
|
||||
const child = flowLayout.children[i]
|
||||
if (child && typeof child.count !== "undefined" && typeof child.itemAt === "function") {
|
||||
repeater = child
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!repeater || !repeater.itemAt) {
|
||||
return null
|
||||
}
|
||||
for (var i = 0; i < repeater.count; i++) {
|
||||
const item = repeater.itemAt(i)
|
||||
if (item && item.dockButton && item.dockButton.showTooltip) {
|
||||
return item.dockButton
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
property string tooltipText: hoveredButton ? hoveredButton.tooltipText : ""
|
||||
|
||||
visible: hoveredButton !== null && tooltipText !== ""
|
||||
width: px(tooltipLabel.implicitWidth + 24)
|
||||
height: px(tooltipLabel.implicitHeight + 12)
|
||||
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 1
|
||||
border.color: Theme.outlineMedium
|
||||
|
||||
x: {
|
||||
if (!hoveredButton) return 0
|
||||
const buttonPos = hoveredButton.mapToItem(dock.contentItem, 0, 0)
|
||||
if (!dock.isVertical) {
|
||||
return buttonPos.x + hoveredButton.width / 2 - width / 2
|
||||
} else {
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Right) {
|
||||
return buttonPos.x - width - Theme.spacingS
|
||||
} else {
|
||||
return buttonPos.x + hoveredButton.width + Theme.spacingS
|
||||
}
|
||||
}
|
||||
}
|
||||
y: {
|
||||
if (!hoveredButton) return 0
|
||||
const buttonPos = hoveredButton.mapToItem(dock.contentItem, 0, 0)
|
||||
if (!dock.isVertical) {
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
|
||||
return buttonPos.y - height - Theme.spacingS
|
||||
} else {
|
||||
return buttonPos.y + hoveredButton.height + Theme.spacingS
|
||||
}
|
||||
} else {
|
||||
return buttonPos.y + hoveredButton.height / 2 - height / 2
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: tooltipLabel
|
||||
anchors.centerIn: parent
|
||||
text: appTooltip.tooltipText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: dockCore
|
||||
anchors.fill: parent
|
||||
@@ -125,14 +212,31 @@ Variants {
|
||||
id: dockMouseArea
|
||||
property real currentScreen: modelData ? modelData : dock.screen
|
||||
property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920
|
||||
property real screenHeight: currentScreen ? currentScreen.geometry.height : 1080
|
||||
property real maxDockWidth: Math.min(screenWidth * 0.8, 1200)
|
||||
property real maxDockHeight: Math.min(screenHeight * 0.8, 1200)
|
||||
|
||||
height: dock.reveal ? px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap) : 1
|
||||
width: dock.reveal ? Math.min(dockBackground.implicitWidth + 32, maxDockWidth) : Math.min(Math.max(dockBackground.implicitWidth + 64, 200), screenWidth * 0.5)
|
||||
height: {
|
||||
if (dock.isVertical) {
|
||||
return dock.reveal ? Math.min(dockBackground.implicitHeight + 32, maxDockHeight) : Math.min(Math.max(dockBackground.implicitHeight + 64, 200), screenHeight * 0.5)
|
||||
} else {
|
||||
return dock.reveal ? px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap) : 1
|
||||
}
|
||||
}
|
||||
width: {
|
||||
if (dock.isVertical) {
|
||||
return dock.reveal ? px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap) : 1
|
||||
} else {
|
||||
return dock.reveal ? Math.min(dockBackground.implicitWidth + 32, maxDockWidth) : Math.min(Math.max(dockBackground.implicitWidth + 64, 200), screenWidth * 0.5)
|
||||
}
|
||||
}
|
||||
anchors {
|
||||
top: SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top
|
||||
bottom: SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top) : undefined
|
||||
bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined) : undefined
|
||||
horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined
|
||||
left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? undefined : parent.left) : undefined
|
||||
right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined
|
||||
verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
|
||||
}
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
@@ -144,6 +248,12 @@ Variants {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: dockContainer
|
||||
@@ -151,7 +261,17 @@ Variants {
|
||||
|
||||
transform: Translate {
|
||||
id: dockSlide
|
||||
x: {
|
||||
if (!dock.isVertical) return 0
|
||||
if (dock.reveal) return 0
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Right) {
|
||||
return 60
|
||||
} else {
|
||||
return -60
|
||||
}
|
||||
}
|
||||
y: {
|
||||
if (dock.isVertical) return 0
|
||||
if (dock.reveal) return 0
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
|
||||
return 60
|
||||
@@ -160,6 +280,13 @@ Variants {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
@@ -172,15 +299,20 @@ Variants {
|
||||
id: dockBackground
|
||||
objectName: "dockBackground"
|
||||
anchors {
|
||||
top: SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top
|
||||
bottom: SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top) : undefined
|
||||
bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined) : undefined
|
||||
horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined
|
||||
left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? undefined : parent.left) : undefined
|
||||
right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined
|
||||
verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
|
||||
}
|
||||
anchors.topMargin: SettingsData.dockPosition === SettingsData.Position.Bottom ? 0 : barSpacing + 4
|
||||
anchors.bottomMargin: SettingsData.dockPosition === SettingsData.Position.Bottom ? barSpacing + 1 : 0
|
||||
anchors.topMargin: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? 0 : barSpacing + 4) : 0
|
||||
anchors.bottomMargin: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? barSpacing + 1 : 0) : 0
|
||||
anchors.leftMargin: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? 0 : barSpacing + 4) : 0
|
||||
anchors.rightMargin: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? barSpacing + 1 : 0) : 0
|
||||
|
||||
implicitWidth: dockApps.implicitWidth + SettingsData.dockSpacing * 2
|
||||
implicitHeight: dockApps.implicitHeight + SettingsData.dockSpacing * 2
|
||||
implicitWidth: dock.isVertical ? (dockApps.implicitHeight + SettingsData.dockSpacing * 2) : (dockApps.implicitWidth + SettingsData.dockSpacing * 2)
|
||||
implicitHeight: dock.isVertical ? (dockApps.implicitWidth + SettingsData.dockSpacing * 2) : (dockApps.implicitHeight + SettingsData.dockSpacing * 2)
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
@@ -199,69 +331,24 @@ Variants {
|
||||
DockApps {
|
||||
id: dockApps
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: SettingsData.dockSpacing
|
||||
anchors.bottomMargin: SettingsData.dockSpacing
|
||||
anchors.top: !dock.isVertical ? parent.top : undefined
|
||||
anchors.bottom: !dock.isVertical ? parent.bottom : undefined
|
||||
anchors.horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined
|
||||
anchors.left: dock.isVertical ? parent.left : undefined
|
||||
anchors.right: dock.isVertical ? parent.right : undefined
|
||||
anchors.verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
|
||||
anchors.topMargin: !dock.isVertical ? SettingsData.dockSpacing : 0
|
||||
anchors.bottomMargin: !dock.isVertical ? SettingsData.dockSpacing : 0
|
||||
anchors.leftMargin: dock.isVertical ? SettingsData.dockSpacing : 0
|
||||
anchors.rightMargin: dock.isVertical ? SettingsData.dockSpacing : 0
|
||||
|
||||
contextMenu: dockVariants.contextMenu
|
||||
groupByApp: dock.groupByApp
|
||||
isVertical: dock.isVertical
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: appTooltip
|
||||
|
||||
property var hoveredButton: {
|
||||
if (!dockApps.children[0]) {
|
||||
return null
|
||||
}
|
||||
const row = dockApps.children[0]
|
||||
let repeater = null
|
||||
for (var i = 0; i < row.children.length; i++) {
|
||||
const child = row.children[i]
|
||||
if (child && typeof child.count !== "undefined" && typeof child.itemAt === "function") {
|
||||
repeater = child
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!repeater || !repeater.itemAt) {
|
||||
return null
|
||||
}
|
||||
for (var i = 0; i < repeater.count; i++) {
|
||||
const item = repeater.itemAt(i)
|
||||
if (item && item.dockButton && item.dockButton.showTooltip) {
|
||||
return item.dockButton
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
property string tooltipText: hoveredButton ? hoveredButton.tooltipText : ""
|
||||
|
||||
visible: hoveredButton !== null && tooltipText !== ""
|
||||
width: px(tooltipLabel.implicitWidth + 24)
|
||||
height: px(tooltipLabel.implicitHeight + 12)
|
||||
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 1
|
||||
border.color: Theme.outlineMedium
|
||||
|
||||
y: SettingsData.dockPosition === SettingsData.Position.Bottom ? -height - Theme.spacingS : parent.height + Theme.spacingS
|
||||
x: hoveredButton ? hoveredButton.mapToItem(dockContainer, hoveredButton.width / 2, 0).x - width / 2 : 0
|
||||
|
||||
StyledText {
|
||||
id: tooltipLabel
|
||||
anchors.centerIn: parent
|
||||
text: appTooltip.tooltipText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,10 @@ Item {
|
||||
property bool requestDockShow: false
|
||||
property int pinnedAppCount: 0
|
||||
property bool groupByApp: false
|
||||
property bool isVertical: false
|
||||
|
||||
implicitWidth: row.width
|
||||
implicitHeight: row.height
|
||||
implicitWidth: isVertical ? appLayout.height : appLayout.width
|
||||
implicitHeight: isVertical ? appLayout.width : appLayout.height
|
||||
|
||||
function movePinnedApp(fromIndex, toIndex) {
|
||||
if (fromIndex === toIndex) {
|
||||
@@ -33,11 +34,16 @@ Item {
|
||||
SessionData.setPinnedApps(currentPinned)
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row
|
||||
spacing: 8
|
||||
Item {
|
||||
id: appLayout
|
||||
anchors.centerIn: parent
|
||||
height: 40
|
||||
width: layoutFlow.width
|
||||
height: layoutFlow.height
|
||||
|
||||
Flow {
|
||||
id: layoutFlow
|
||||
flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight
|
||||
spacing: 8
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
@@ -218,6 +224,7 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
||||
@@ -92,24 +92,41 @@ PanelWindow {
|
||||
}
|
||||
|
||||
const dockBackground = findDockBackground(dockWindow.contentItem)
|
||||
let actualDockWidth = dockWindow.width
|
||||
if (dockBackground) {
|
||||
actualDockHeight = dockBackground.height
|
||||
actualDockWidth = dockBackground.width
|
||||
}
|
||||
|
||||
const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom
|
||||
const dockBottomMargin = 16
|
||||
let buttonScreenY
|
||||
const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
||||
const dockMargin = 16
|
||||
let buttonScreenX, buttonScreenY
|
||||
|
||||
if (isDockAtBottom) {
|
||||
buttonScreenY = root.screen.height - actualDockHeight - dockBottomMargin - 20
|
||||
if (isVertical) {
|
||||
const dockContentHeight = dockWindow.height
|
||||
const screenHeight = root.screen.height
|
||||
const dockTopMargin = Math.round((screenHeight - dockContentHeight) / 2)
|
||||
buttonScreenY = dockTopMargin + buttonPosInDock.y + anchorItem.height / 2
|
||||
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Right) {
|
||||
buttonScreenX = root.screen.width - actualDockWidth - dockMargin - 20
|
||||
} else {
|
||||
buttonScreenX = actualDockWidth + dockMargin + 20
|
||||
}
|
||||
} else {
|
||||
buttonScreenY = actualDockHeight + dockBottomMargin + 20
|
||||
}
|
||||
const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom
|
||||
|
||||
const dockContentWidth = dockWindow.width
|
||||
const screenWidth = root.screen.width
|
||||
const dockLeftMargin = Math.round((screenWidth - dockContentWidth) / 2)
|
||||
const buttonScreenX = dockLeftMargin + buttonPosInDock.x + anchorItem.width / 2
|
||||
if (isDockAtBottom) {
|
||||
buttonScreenY = root.screen.height - actualDockHeight - dockMargin - 20
|
||||
} else {
|
||||
buttonScreenY = actualDockHeight + dockMargin + 20
|
||||
}
|
||||
|
||||
const dockContentWidth = dockWindow.width
|
||||
const screenWidth = root.screen.width
|
||||
const dockLeftMargin = Math.round((screenWidth - dockContentWidth) / 2)
|
||||
buttonScreenX = dockLeftMargin + buttonPosInDock.x + anchorItem.width / 2
|
||||
}
|
||||
|
||||
anchorPos = Qt.point(buttonScreenX, buttonScreenY)
|
||||
}
|
||||
@@ -121,17 +138,35 @@ PanelWindow {
|
||||
height: Math.max(60, menuColumn.implicitHeight + Theme.spacingS * 2)
|
||||
|
||||
x: {
|
||||
const left = 10
|
||||
const right = root.width - width - 10
|
||||
const want = root.anchorPos.x - width / 2
|
||||
return Math.max(left, Math.min(right, want))
|
||||
const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
||||
if (isVertical) {
|
||||
const isDockAtRight = SettingsData.dockPosition === SettingsData.Position.Right
|
||||
if (isDockAtRight) {
|
||||
return Math.max(10, root.anchorPos.x - width + 30)
|
||||
} else {
|
||||
return Math.min(root.width - width - 10, root.anchorPos.x - 30)
|
||||
}
|
||||
} else {
|
||||
const left = 10
|
||||
const right = root.width - width - 10
|
||||
const want = root.anchorPos.x - width / 2
|
||||
return Math.max(left, Math.min(right, want))
|
||||
}
|
||||
}
|
||||
y: {
|
||||
const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom
|
||||
if (isDockAtBottom) {
|
||||
return Math.max(10, root.anchorPos.y - height + 30)
|
||||
const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
||||
if (isVertical) {
|
||||
const top = 10
|
||||
const bottom = root.height - height - 10
|
||||
const want = root.anchorPos.y - height / 2
|
||||
return Math.max(top, Math.min(bottom, want))
|
||||
} else {
|
||||
return Math.min(root.height - height - 10, root.anchorPos.y - 30)
|
||||
const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom
|
||||
if (isDockAtBottom) {
|
||||
return Math.max(10, root.anchorPos.y - height + 30)
|
||||
} else {
|
||||
return Math.min(root.height - height - 10, root.anchorPos.y - 30)
|
||||
}
|
||||
}
|
||||
}
|
||||
color: Theme.popupBackground()
|
||||
|
||||
105
Modules/Greetd/GreetdMemory.qml
Normal file
105
Modules/Greetd/GreetdMemory.qml
Normal file
@@ -0,0 +1,105 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property string greetCfgDir: Quickshell.env("DMS_GREET_CFG_DIR") || "/etc/greetd/.dms"
|
||||
readonly property string sessionConfigPath: greetCfgDir + "/session.json"
|
||||
readonly property string memoryFile: greetCfgDir + "/memory.json"
|
||||
|
||||
property string lastSessionId: ""
|
||||
property string lastSuccessfulUser: ""
|
||||
property bool isLightMode: false
|
||||
property bool nightModeEnabled: false
|
||||
|
||||
Component.onCompleted: {
|
||||
Quickshell.execDetached(["mkdir", "-p", greetCfgDir])
|
||||
loadMemory()
|
||||
loadSessionConfig()
|
||||
}
|
||||
|
||||
function loadMemory() {
|
||||
parseMemory(memoryFileView.text())
|
||||
}
|
||||
|
||||
function loadSessionConfig() {
|
||||
parseSessionConfig(sessionConfigFileView.text())
|
||||
}
|
||||
|
||||
function parseSessionConfig(content) {
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
const config = JSON.parse(content)
|
||||
isLightMode = config.isLightMode !== undefined ? config.isLightMode : false
|
||||
nightModeEnabled = config.nightModeEnabled !== undefined ? config.nightModeEnabled : false
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse greeter session config:", e)
|
||||
}
|
||||
}
|
||||
|
||||
function parseMemory(content) {
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
const memory = JSON.parse(content)
|
||||
lastSessionId = memory.lastSessionId !== undefined ? memory.lastSessionId : ""
|
||||
lastSuccessfulUser = memory.lastSuccessfulUser !== undefined ? memory.lastSuccessfulUser : ""
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse greetd memory:", e)
|
||||
}
|
||||
}
|
||||
|
||||
function saveMemory() {
|
||||
memoryFileView.setText(JSON.stringify({
|
||||
"lastSessionId": lastSessionId,
|
||||
"lastSuccessfulUser": lastSuccessfulUser
|
||||
}, null, 2))
|
||||
}
|
||||
|
||||
function setLastSessionId(id) {
|
||||
lastSessionId = id || ""
|
||||
saveMemory()
|
||||
}
|
||||
|
||||
function setLastSuccessfulUser(username) {
|
||||
lastSuccessfulUser = username || ""
|
||||
saveMemory()
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: memoryFileView
|
||||
path: root.memoryFile
|
||||
blockLoading: false
|
||||
blockWrites: false
|
||||
atomicWrites: true
|
||||
watchChanges: false
|
||||
printErrors: false
|
||||
onLoaded: {
|
||||
parseMemory(memoryFileView.text())
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: sessionConfigFileView
|
||||
path: root.sessionConfigPath
|
||||
blockLoading: false
|
||||
blockWrites: true
|
||||
atomicWrites: false
|
||||
watchChanges: false
|
||||
printErrors: true
|
||||
onLoaded: {
|
||||
parseSessionConfig(sessionConfigFileView.text())
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
console.warn("Could not load greeter session config from", root.sessionConfigPath, "error:", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
114
Modules/Greetd/GreetdSettings.qml
Normal file
114
Modules/Greetd/GreetdSettings.qml
Normal file
@@ -0,0 +1,114 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property string configPath: {
|
||||
const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/etc/greetd/.dms"
|
||||
return greetCfgDir + "/settings.json"
|
||||
}
|
||||
|
||||
property string currentThemeName: "blue"
|
||||
property bool settingsLoaded: false
|
||||
property string customThemeFile: ""
|
||||
property string matugenScheme: "scheme-tonal-spot"
|
||||
property bool use24HourClock: true
|
||||
property bool useFahrenheit: false
|
||||
property bool nightModeEnabled: false
|
||||
property string weatherLocation: "New York, NY"
|
||||
property string weatherCoordinates: "40.7128,-74.0060"
|
||||
property bool useAutoLocation: false
|
||||
property bool weatherEnabled: true
|
||||
property string iconTheme: "System Default"
|
||||
property bool useOSLogo: false
|
||||
property string osLogoColorOverride: ""
|
||||
property real osLogoBrightness: 0.5
|
||||
property real osLogoContrast: 1
|
||||
property string fontFamily: "Inter Variable"
|
||||
property string monoFontFamily: "Fira Code"
|
||||
property int fontWeight: Font.Normal
|
||||
property real fontScale: 1.0
|
||||
property real cornerRadius: 12
|
||||
property string widgetBackgroundColor: "sch"
|
||||
property string surfaceBase: "s"
|
||||
property string lockDateFormat: ""
|
||||
property bool lockScreenShowPowerActions: true
|
||||
property var screenPreferences: ({})
|
||||
property int animationSpeed: 2
|
||||
|
||||
readonly property string defaultFontFamily: "Inter Variable"
|
||||
readonly property string defaultMonoFontFamily: "Fira Code"
|
||||
|
||||
function parseSettings(content) {
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
const settings = JSON.parse(content)
|
||||
currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "blue"
|
||||
customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : ""
|
||||
matugenScheme = settings.matugenScheme !== undefined ? settings.matugenScheme : "scheme-tonal-spot"
|
||||
use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true
|
||||
useFahrenheit = settings.useFahrenheit !== undefined ? settings.useFahrenheit : false
|
||||
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false
|
||||
weatherLocation = settings.weatherLocation !== undefined ? settings.weatherLocation : "New York, NY"
|
||||
weatherCoordinates = settings.weatherCoordinates !== undefined ? settings.weatherCoordinates : "40.7128,-74.0060"
|
||||
useAutoLocation = settings.useAutoLocation !== undefined ? settings.useAutoLocation : false
|
||||
weatherEnabled = settings.weatherEnabled !== undefined ? settings.weatherEnabled : true
|
||||
iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default"
|
||||
useOSLogo = settings.useOSLogo !== undefined ? settings.useOSLogo : false
|
||||
osLogoColorOverride = settings.osLogoColorOverride !== undefined ? settings.osLogoColorOverride : ""
|
||||
osLogoBrightness = settings.osLogoBrightness !== undefined ? settings.osLogoBrightness : 0.5
|
||||
osLogoContrast = settings.osLogoContrast !== undefined ? settings.osLogoContrast : 1
|
||||
fontFamily = settings.fontFamily !== undefined ? settings.fontFamily : defaultFontFamily
|
||||
monoFontFamily = settings.monoFontFamily !== undefined ? settings.monoFontFamily : defaultMonoFontFamily
|
||||
fontWeight = settings.fontWeight !== undefined ? settings.fontWeight : Font.Normal
|
||||
fontScale = settings.fontScale !== undefined ? settings.fontScale : 1.0
|
||||
cornerRadius = settings.cornerRadius !== undefined ? settings.cornerRadius : 12
|
||||
widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"
|
||||
surfaceBase = settings.surfaceBase !== undefined ? settings.surfaceBase : "s"
|
||||
lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : ""
|
||||
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true
|
||||
screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({})
|
||||
animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : 2
|
||||
settingsLoaded = true
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.applyGreeterTheme(currentThemeName)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse greetd settings:", e)
|
||||
}
|
||||
}
|
||||
|
||||
function getEffectiveLockDateFormat() {
|
||||
return lockDateFormat && lockDateFormat.length > 0 ? lockDateFormat : Locale.LongFormat
|
||||
}
|
||||
|
||||
function getFilteredScreens(componentId) {
|
||||
const prefs = screenPreferences && screenPreferences[componentId] || ["all"]
|
||||
if (prefs.includes("all")) {
|
||||
return Quickshell.screens
|
||||
}
|
||||
return Quickshell.screens.filter(screen => prefs.includes(screen.name))
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: settingsFile
|
||||
path: root.configPath
|
||||
blockLoading: false
|
||||
blockWrites: true
|
||||
atomicWrites: false
|
||||
watchChanges: false
|
||||
printErrors: true
|
||||
onLoaded: {
|
||||
parseSettings(settingsFile.text())
|
||||
}
|
||||
}
|
||||
}
|
||||
1214
Modules/Greetd/GreeterContent.qml
Normal file
1214
Modules/Greetd/GreeterContent.qml
Normal file
File diff suppressed because it is too large
Load Diff
28
Modules/Greetd/GreeterState.qml
Normal file
28
Modules/Greetd/GreeterState.qml
Normal file
@@ -0,0 +1,28 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property string passwordBuffer: ""
|
||||
property string username: ""
|
||||
property string usernameInput: ""
|
||||
property bool showPasswordInput: false
|
||||
property string selectedSession: ""
|
||||
property string pamState: ""
|
||||
property bool unlocking: false
|
||||
|
||||
property var sessionList: []
|
||||
property var sessionExecs: []
|
||||
property int currentSessionIndex: 0
|
||||
|
||||
function reset() {
|
||||
showPasswordInput = false
|
||||
username = ""
|
||||
usernameInput = ""
|
||||
passwordBuffer = ""
|
||||
pamState = ""
|
||||
}
|
||||
}
|
||||
18
Modules/Greetd/GreeterSurface.qml
Normal file
18
Modules/Greetd/GreeterSurface.qml
Normal file
@@ -0,0 +1,18 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Services.Greetd
|
||||
|
||||
WlSessionLockSurface {
|
||||
id: root
|
||||
|
||||
required property WlSessionLock lock
|
||||
|
||||
color: "transparent"
|
||||
|
||||
GreeterContent {
|
||||
anchors.fill: parent
|
||||
screenName: root.screen?.name ?? ""
|
||||
sessionLock: root.lock
|
||||
}
|
||||
}
|
||||
79
Modules/Greetd/README.md
Normal file
79
Modules/Greetd/README.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# Dank (dms) Greeter
|
||||
|
||||
A greeter for [greetd](https://github.com/kennylevinsen/greetd) that follows the aesthetics of the dms lock screen.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi user**: Login with any system user
|
||||
- **dms sync**: Sync settings with dms for consistent styling between shell and greeter
|
||||
- **niri or Hyprland**: Use either niri or Hyprland for the greeter's compositor.
|
||||
- **Custom PAM**: Supports custom PAM configuration in `/etc/pam.d/dankshell`
|
||||
- **Session Memory**: Remembers last selected session and user
|
||||
|
||||
## Installation
|
||||
|
||||
The easiest thing is to run `dms greeter install` or `dms` for interactive installation.
|
||||
|
||||
Manual installation:
|
||||
1. Install `greetd` (in most distro's standard repositories)
|
||||
2. Copy `assets/dms-niri.kdl` or `assets/dms-hypr.conf` to `/etc/greetd`
|
||||
- niri if you want to run the greeter under niri, hypr if you want to run the greeter under Hyprland
|
||||
3. Copy `assets/greet-niri.sh` or `assets/greet-hyprland.sh` to `/etc/greetd/start-dms.sh`
|
||||
4. Edit `/etc/greetd/dms-niri.kdl` or `/etc/greetd/dms-hypr.conf` and replace `_DMS_PATH_` with the absolute path to dms, e.g. `/home/joecool/.config/quickshell/dms`
|
||||
5. Edit or create `/etc/greetd/config.toml`
|
||||
```toml
|
||||
[terminal]
|
||||
# The VT to run the greeter on. Can be "next", "current" or a number
|
||||
# designating the VT.
|
||||
vt = 1
|
||||
|
||||
# The default session, also known as the greeter.
|
||||
[default_session]
|
||||
|
||||
# `agreety` is the bundled agetty/login-lookalike. You can replace `/bin/sh`
|
||||
# with whatever you want started, such as `sway`.
|
||||
|
||||
# The user to run the command as. The privileges this user must have depends
|
||||
# on the greeter. A graphical greeter may for example require the user to be
|
||||
# in the `video` group.
|
||||
user = "greeter"
|
||||
|
||||
command = "/etc/greetd/start-dms.sh"%
|
||||
```
|
||||
|
||||
Enable the greeter with `sudo systemctl enable greetd`
|
||||
|
||||
## Usage
|
||||
|
||||
To run dms in greeter mode you just need to set `DMS_RUN_GREETER=1` in the environment.
|
||||
|
||||
```bash
|
||||
DMS_RUN_GREETER=1 qs -p /path/to/dms
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
#### Compositor
|
||||
|
||||
You can configure compositor specific settings such as outputs/displays the same as you would in niri or Hyprland.
|
||||
|
||||
Simply edit `/etc/greetd/dms-niri.kdl` or `/etc/greetd/dms-hypr.conf` to change compositor settings for the greeter
|
||||
|
||||
#### Personalization
|
||||
|
||||
Wallpapers and themes and weather and clock formats and things are a TODO on the documentation, but it's configured exactly the same as dms.
|
||||
|
||||
You can synchronize those configurations with a specific user if you want greeter settings to always mirror the shell.
|
||||
|
||||
```bash
|
||||
# For core settings (theme, clock formats, etc)
|
||||
sudo ln -sf ~/.config/DankMaterialShell/settings.json /etc/greetd/.dms/settings.json
|
||||
# For state (mainly you would configure wallpaper in this file)
|
||||
sudo ln -sf ~/.local/state/DankMaterialShell/session.json /etc/greetd/.dms/session.json
|
||||
# For wallpaper based theming
|
||||
sudo ln -sf ~/.cache/quickshell/dankshell/dms-colors.json /etc/greetd/.dms/dms-colors.json
|
||||
```
|
||||
|
||||
You can override the configuration path with the `DMS_GREET_CFG_DIR` environment variable, the default is `/etc/greetd/.dms`
|
||||
|
||||
It should be writable by the greeter user.
|
||||
6
Modules/Greetd/assets/dms-hypr.conf
Normal file
6
Modules/Greetd/assets/dms-hypr.conf
Normal file
@@ -0,0 +1,6 @@
|
||||
env = DMS_RUN_GREETER,1
|
||||
env = QT_QPA_PLATFORM,wayland
|
||||
env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1
|
||||
env = EGL_PLATFORM,gbm
|
||||
|
||||
exec = sh -c "qs -p _DMS_PATH_; hyprctl dispatch exit"
|
||||
21
Modules/Greetd/assets/dms-niri.kdl
Normal file
21
Modules/Greetd/assets/dms-niri.kdl
Normal file
@@ -0,0 +1,21 @@
|
||||
hotkey-overlay {
|
||||
skip-at-startup
|
||||
}
|
||||
|
||||
environment {
|
||||
DMS_RUN_GREETER "1"
|
||||
QT_QPA_PLATFORM "wayland"
|
||||
QT_WAYLAND_DISABLE_WINDOWDECORATION "1"
|
||||
}
|
||||
|
||||
spawn-at-startup "sh" "-c" "qs -p _DMS_PATH_; niri msg action quit --skip-confirmation"
|
||||
|
||||
debug {
|
||||
keep-max-bpc-unchanged
|
||||
}
|
||||
|
||||
gestures {
|
||||
hot-corners {
|
||||
off
|
||||
}
|
||||
}
|
||||
3
Modules/Greetd/assets/greet-hyprland.sh
Executable file
3
Modules/Greetd/assets/greet-hyprland.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
EGL_PLATFORM=gbm Hyprland -c /etc/greetd/dms-hypr.conf
|
||||
3
Modules/Greetd/assets/greet-niri.sh
Executable file
3
Modules/Greetd/assets/greet-niri.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
EGL_PLATFORM=gbm niri -c /etc/greetd/dms-niri.kdl
|
||||
@@ -44,10 +44,8 @@ Item {
|
||||
powerDialogVisible = false
|
||||
}
|
||||
|
||||
property var facts: ["A photon takes 100,000 to 200,000 years bouncing through the Sun's dense core, then races to Earth in just 8 minutes 20 seconds.", "A teaspoon of neutron star matter would weigh a billion metric tons here on Earth.", "Right now, 100 trillion solar neutrinos are passing through your body every second.", "The Sun converts 4 million metric tons of matter into pure energy every second—enough to power Earth for 500,000 years.", "The universe still glows with leftover heat from the Big Bang—just 2.7 degrees above absolute zero.", "There's a nebula out there that's actually colder than empty space itself.", "We've detected black holes crashing together by measuring spacetime stretch by less than 1/10,000th the width of a proton.", "Fast radio bursts can release more energy in 5 milliseconds than our Sun produces in 3 days.", "Our galaxy might be crawling with billions of rogue planets drifting alone in the dark.", "Distant galaxies can move away from us faster than light because space itself is stretching.", "The edge of what we can see is 46.5 billion light-years away, even though the universe is only 13.8 billion years old.", "The universe is mostly invisible: 5% regular matter, 27% dark matter, 68% dark energy.", "A day on Venus lasts longer than its entire year around the Sun.", "On Mercury, the time between sunrises is 176 Earth days long.", "In about 4.5 billion years, our galaxy will smash into Andromeda.", "Most of the gold in your jewelry was forged when neutron stars collided somewhere in space.", "PSR J1748-2446ad, the fastest spinning star, rotates 716 times per second—its equator moves at 24% the speed of light.", "Cosmic rays create particles that shouldn't make it to Earth's surface, but time dilation lets them sneak through.", "Jupiter's magnetic field is so huge that if we could see it, it would look bigger than the Moon in our sky.", "Interstellar space is so empty it's like a cube 32 kilometers wide containing just a single grain of sand.", "Voyager 1 is 24 billion kilometers away but won't leave the Sun's gravitational influence for another 30,000 years.", "Counting to a billion at one number per second would take over 31 years.", "Space is so vast, even speeding at light-speed, you'd never return past the cosmic horizon.", "Astronauts on the ISS age about 0.01 seconds less each year than people on Earth.", "Sagittarius B2, a dust cloud near our galaxy's center, contains ethyl formate—the compound that gives raspberries their flavor and rum its smell.", "Beyond 16 billion light-years, the cosmic event horizon marks where space expands too fast for light to ever reach us again.", "Even at light-speed, you'd never catch up to most galaxies—space expands faster.", "Only around 5% of galaxies are ever reachable—even at light-speed.", "If the Sun vanished, we'd still orbit it for 8 minutes before drifting away.", "If a planet 65 million light-years away looked at Earth now, it'd see dinosaurs.", "Our oldest radio signals will reach the Milky Way's center in 26,000 years.", "Every atom in your body heavier than hydrogen was forged in the nuclear furnace of a dying star.", "The Moon moves 3.8 centimeters farther from Earth every year.", "The universe creates 275 million new stars every single day.", "Jupiter's Great Red Spot is a storm twice the size of Earth that has been raging for at least 350 years.", "If you watched someone fall into a black hole, they'd appear frozen at the event horizon forever—time effectively stops from your perspective.", "The Boötes Supervoid is a cosmic desert 1.8 billion light-years across with 60% fewer galaxies than it should have."]
|
||||
|
||||
function pickRandomFact() {
|
||||
randomFact = facts[Math.floor(Math.random() * facts.length)]
|
||||
randomFact = Facts.getRandomFact()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
@@ -180,93 +178,21 @@ Item {
|
||||
spacing: Theme.spacingL
|
||||
Layout.fillWidth: true
|
||||
|
||||
Item {
|
||||
id: avatarContainer
|
||||
|
||||
property bool hasImage: profileImageLoader.status === Image.Ready
|
||||
|
||||
DankCircularImage {
|
||||
Layout.preferredWidth: 60
|
||||
Layout.preferredHeight: 60
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: width / 2
|
||||
color: "transparent"
|
||||
border.color: Theme.primary
|
||||
border.width: 1
|
||||
visible: parent.hasImage
|
||||
}
|
||||
|
||||
Image {
|
||||
id: profileImageLoader
|
||||
|
||||
source: {
|
||||
if (PortalService.profileImage === "") {
|
||||
return ""
|
||||
}
|
||||
|
||||
if (PortalService.profileImage.startsWith("/")) {
|
||||
return "file://" + PortalService.profileImage
|
||||
}
|
||||
|
||||
return PortalService.profileImage
|
||||
imageSource: {
|
||||
if (PortalService.profileImage === "") {
|
||||
return ""
|
||||
}
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
mipmap: true
|
||||
cache: true
|
||||
visible: false
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 5
|
||||
source: profileImageLoader
|
||||
maskEnabled: true
|
||||
maskSource: circularMask
|
||||
visible: avatarContainer.hasImage
|
||||
maskThresholdMin: 0.5
|
||||
maskSpreadAtMin: 1
|
||||
}
|
||||
|
||||
Item {
|
||||
id: circularMask
|
||||
|
||||
width: 60 - 10
|
||||
height: 60 - 10
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
visible: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: width / 2
|
||||
color: "black"
|
||||
antialiasing: true
|
||||
if (PortalService.profileImage.startsWith("/")) {
|
||||
return "file://" + PortalService.profileImage
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: width / 2
|
||||
color: Theme.primary
|
||||
visible: !parent.hasImage
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "person"
|
||||
size: Theme.iconSize + 4
|
||||
color: Theme.primaryText
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "warning"
|
||||
size: Theme.iconSize + 4
|
||||
color: Theme.primaryText
|
||||
visible: PortalService.profileImage !== "" && profileImageLoader.status === Image.Error
|
||||
return PortalService.profileImage
|
||||
}
|
||||
fallbackIcon: "person"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
||||
@@ -411,6 +411,78 @@ QtObject {
|
||||
selectPrevious()
|
||||
event.accepted = true
|
||||
}
|
||||
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
|
||||
if (!keyboardNavigationActive) {
|
||||
keyboardNavigationActive = true
|
||||
rebuildFlatNavigation()
|
||||
selectedFlatIndex = 0
|
||||
updateSelectedIdFromIndex()
|
||||
if (listView) {
|
||||
listView.keyboardActive = true
|
||||
}
|
||||
selectionVersion++
|
||||
ensureVisible()
|
||||
} else {
|
||||
selectNext()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
|
||||
if (!keyboardNavigationActive) {
|
||||
keyboardNavigationActive = true
|
||||
rebuildFlatNavigation()
|
||||
selectedFlatIndex = 0
|
||||
updateSelectedIdFromIndex()
|
||||
if (listView) {
|
||||
listView.keyboardActive = true
|
||||
}
|
||||
selectionVersion++
|
||||
ensureVisible()
|
||||
} else if (selectedFlatIndex === 0) {
|
||||
keyboardNavigationActive = false
|
||||
if (listView) {
|
||||
listView.keyboardActive = false
|
||||
}
|
||||
selectionVersion++
|
||||
} else {
|
||||
selectPrevious()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
|
||||
if (!keyboardNavigationActive) {
|
||||
keyboardNavigationActive = true
|
||||
rebuildFlatNavigation()
|
||||
selectedFlatIndex = 0
|
||||
updateSelectedIdFromIndex()
|
||||
if (listView) {
|
||||
listView.keyboardActive = true
|
||||
}
|
||||
selectionVersion++
|
||||
ensureVisible()
|
||||
} else {
|
||||
selectNext()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
|
||||
if (!keyboardNavigationActive) {
|
||||
keyboardNavigationActive = true
|
||||
rebuildFlatNavigation()
|
||||
selectedFlatIndex = 0
|
||||
updateSelectedIdFromIndex()
|
||||
if (listView) {
|
||||
listView.keyboardActive = true
|
||||
}
|
||||
selectionVersion++
|
||||
ensureVisible()
|
||||
} else if (selectedFlatIndex === 0) {
|
||||
keyboardNavigationActive = false
|
||||
if (listView) {
|
||||
listView.keyboardActive = false
|
||||
}
|
||||
selectionVersion++
|
||||
} else {
|
||||
selectPrevious()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (keyboardNavigationActive) {
|
||||
if (event.key === Qt.Key_Space) {
|
||||
toggleGroupExpanded()
|
||||
|
||||
@@ -65,11 +65,24 @@ Item {
|
||||
DankButtonGroup {
|
||||
id: positionButtonGroup
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
model: ["Top", "Bottom"]
|
||||
currentIndex: SettingsData.dockPosition === SettingsData.Position.Bottom ? 1 : 0
|
||||
model: ["Top", "Bottom", "Left", "Right"]
|
||||
currentIndex: {
|
||||
switch (SettingsData.dockPosition) {
|
||||
case SettingsData.Position.Top: return 0
|
||||
case SettingsData.Position.Bottom: return 1
|
||||
case SettingsData.Position.Left: return 2
|
||||
case SettingsData.Position.Right: return 3
|
||||
default: return 1
|
||||
}
|
||||
}
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (selected) {
|
||||
SettingsData.setDockPosition(index === 1 ? SettingsData.Position.Bottom : SettingsData.Position.Top)
|
||||
switch (index) {
|
||||
case 0: SettingsData.setDockPosition(SettingsData.Position.Top); break
|
||||
case 1: SettingsData.setDockPosition(SettingsData.Position.Bottom); break
|
||||
case 2: SettingsData.setDockPosition(SettingsData.Position.Left); break
|
||||
case 3: SettingsData.setDockPosition(SettingsData.Position.Right); break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,7 +183,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Display a dock with pinned and running applications that can be positioned at the top or bottom of the screen"
|
||||
text: "Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
@@ -1702,6 +1702,77 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Animation Settings
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: animationSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
id: animationSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "animation"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Animations"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Animation Speed"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Control the speed of animations throughout the interface"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
DankButtonGroup {
|
||||
id: animationSpeedGroup
|
||||
width: parent.width
|
||||
model: ["None", "Shortest", "Short", "Medium", "Long"]
|
||||
selectionMode: "single"
|
||||
currentIndex: SettingsData.animationSpeed
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (selected) {
|
||||
SettingsData.setAnimationSpeed(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lock Screen Settings
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
|
||||
@@ -120,6 +120,18 @@ Popup {
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
root.selectPrevious()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectNext()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectPrevious()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectNext()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectPrevious()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
if (root.keyboardNavigationActive) {
|
||||
root.selectWidget()
|
||||
|
||||
@@ -11,7 +11,12 @@ LazyLoader {
|
||||
active: true
|
||||
|
||||
Variants {
|
||||
model: SettingsData.getFilteredScreens("wallpaper")
|
||||
model: {
|
||||
if (SessionData.isGreeterMode) {
|
||||
return Quickshell.screens
|
||||
}
|
||||
return SettingsData.getFilteredScreens("wallpaper")
|
||||
}
|
||||
|
||||
PanelWindow {
|
||||
id: wallpaperWindow
|
||||
|
||||
Reference in New Issue
Block a user