1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

handle new ConfigReloaded event

This commit is contained in:
bbedward
2025-08-17 12:27:52 -04:00
parent d8082f70b3
commit 24b44186bd
4 changed files with 253 additions and 44 deletions

View File

@@ -3,6 +3,7 @@ import QtQuick.Effects
import Quickshell
import Quickshell.Wayland
import Quickshell.Widgets
import Quickshell.Io
import qs.Common
import qs.Services
import qs.Widgets
@@ -29,7 +30,16 @@ PanelWindow {
Rectangle {
id: toast
width: Math.min(400, Screen.width - Theme.spacingL * 2)
property bool expanded: false
Connections {
target: ToastService
function onResetToastState() {
toast.expanded = false
}
}
width: ToastService.hasDetails ? 380 : messageText.implicitWidth + Theme.iconSize + Theme.spacingM * 3 + Theme.spacingL * 2
height: toastContent.height + Theme.spacingL * 2
anchors.horizontalCenter: parent.horizontalCenter
y: Theme.barHeight + Theme.spacingL
@@ -48,45 +58,162 @@ PanelWindow {
radius: Theme.cornerRadius
layer.enabled: true
opacity: ToastService.toastVisible ? 0.9 : 0
scale: ToastService.toastVisible ? 1 : 0.9
Row {
Column {
id: toastContent
anchors.centerIn: parent
spacing: Theme.spacingM
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: Theme.spacingL
anchors.leftMargin: Theme.spacingL
anchors.rightMargin: Theme.spacingL
spacing: Theme.spacingS
DankIcon {
name: {
switch (ToastService.currentLevel) {
case ToastService.levelError:
return "error"
case ToastService.levelWarn:
return "warning"
case ToastService.levelInfo:
return "info"
default:
return "info"
Item {
width: parent.width
height: Theme.iconSize + 8
DankIcon {
id: statusIcon
name: {
switch (ToastService.currentLevel) {
case ToastService.levelError:
return "error"
case ToastService.levelWarn:
return "warning"
case ToastService.levelInfo:
return "info"
default:
return "info"
}
}
size: Theme.iconSize
color: Theme.background
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
id: messageText
text: ToastService.currentMessage
font.pixelSize: Theme.fontSizeMedium
color: Theme.background
font.weight: Font.Medium
anchors.left: statusIcon.right
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
wrapMode: Text.NoWrap
}
DankActionButton {
iconName: toast.expanded ? "expand_less" : "expand_more"
iconSize: Theme.iconSize
iconColor: Theme.background
buttonSize: Theme.iconSize + 8
anchors.right: closeButton.left
anchors.rightMargin: 2
anchors.verticalCenter: parent.verticalCenter
visible: ToastService.hasDetails
onClicked: {
toast.expanded = !toast.expanded
if (toast.expanded) {
ToastService.stopTimer()
} else {
ToastService.restartTimer()
}
}
}
DankActionButton {
id: closeButton
iconName: "close"
iconSize: Theme.iconSize
iconColor: Theme.background
buttonSize: Theme.iconSize + 8
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
visible: ToastService.hasDetails
onClicked: {
ToastService.hideToast()
}
}
size: Theme.iconSize
color: Theme.background
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: ToastService.currentMessage
font.pixelSize: Theme.fontSizeMedium
color: Theme.background
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
width: 300
wrapMode: Text.WordWrap
Rectangle {
width: parent.width
height: detailsText.height + Theme.spacingS * 2
color: Qt.rgba(0, 0, 0, 0.2)
radius: Theme.cornerRadius / 2
visible: toast.expanded && ToastService.hasDetails
anchors.horizontalCenter: parent.horizontalCenter
StyledText {
id: detailsText
text: ToastService.currentDetails
font.pixelSize: Theme.fontSizeSmall
color: Theme.background
font.family: "JetBrains Mono"
anchors.left: parent.left
anchors.right: copyButton.left
anchors.verticalCenter: parent.verticalCenter
anchors.margins: Theme.spacingS
anchors.rightMargin: Theme.spacingS
wrapMode: Text.Wrap
}
DankActionButton {
id: copyButton
iconName: "content_copy"
iconSize: Theme.iconSizeSmall
iconColor: Theme.background
buttonSize: Theme.iconSizeSmall + 8
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: Theme.spacingS
property bool showTooltip: false
onClicked: {
Quickshell.execDetached(["wl-copy", ToastService.currentDetails])
showTooltip = true
tooltipTimer.start()
}
Timer {
id: tooltipTimer
interval: 1500
onTriggered: copyButton.showTooltip = false
}
Rectangle {
visible: copyButton.showTooltip
width: tooltipLabel.implicitWidth + 16
height: tooltipLabel.implicitHeight + 8
color: Theme.surfaceContainer
radius: Theme.cornerRadius
border.width: 1
border.color: Theme.outlineMedium
y: -height - 4
x: -width / 2 + copyButton.width / 2
StyledText {
id: tooltipLabel
anchors.centerIn: parent
text: "Copied!"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
}
}
}
}
}
MouseArea {
anchors.fill: parent
visible: !ToastService.hasDetails
onClicked: ToastService.hideToast()
}
@@ -110,12 +237,6 @@ PanelWindow {
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on color {
ColorAnimation {
@@ -123,6 +244,18 @@ PanelWindow {
easing.type: Theme.standardEasing
}
}
Behavior on height {
enabled: ToastService.toastVisible
NumberAnimation {
duration: Anims.durShort
easing.type: Easing.Linear
}
}
Behavior on width {
enabled: false
}
}
mask: Region {

View File

@@ -26,6 +26,10 @@ Singleton {
// Overview state
property bool inOverview: false
// Config validation
property string configValidationOutput: ""
property bool hasInitialConnection: false
signal windowOpenedOrChanged(var windowData)
// Feature availability
@@ -97,6 +101,8 @@ Singleton {
handleWindowOpenedOrChanged(event.WindowOpenedOrChanged)
} else if (event.OverviewOpenedOrClosed) {
handleOverviewChanged(event.OverviewOpenedOrClosed)
} else if (event.ConfigLoaded) {
handleConfigLoaded(event.ConfigLoaded)
}
}
@@ -248,6 +254,48 @@ Singleton {
inOverview = data.is_open
}
function handleConfigLoaded(data) {
if (data.failed) {
validateProcess.running = true
} else {
configValidationOutput = ""
if (ToastService.toastVisible && ToastService.currentLevel === ToastService.levelError) {
ToastService.hideToast()
}
if (hasInitialConnection) {
ToastService.showInfo("niri: config reloaded")
}
}
if (!hasInitialConnection) {
hasInitialConnection = true
}
}
Process {
id: validateProcess
command: ["niri", "validate"]
running: false
stderr: StdioCollector {
onStreamFinished: {
const lines = text.split('\n')
const trimmedLines = lines.map(line => line.replace(/\s+$/, ''))
.filter(line => line.length > 0)
configValidationOutput = trimmedLines.join('\n').trim()
if (hasInitialConnection) {
ToastService.showError("niri: failed to load config", configValidationOutput)
}
}
}
onExited: exitCode => {
if (exitCode === 0) {
configValidationOutput = ""
}
}
}
function updateCurrentOutputWorkspaces() {
if (!currentOutput) {
currentOutputWorkspaces = allWorkspaces

View File

@@ -15,34 +15,40 @@ Singleton {
property int currentLevel: levelInfo
property bool toastVisible: false
property var toastQueue: []
property string currentDetails: ""
property bool hasDetails: false
property string wallpaperErrorStatus: ""
function showToast(message, level = levelInfo) {
function showToast(message, level = levelInfo, details = "") {
toastQueue.push({
"message": message,
"level": level
"level": level,
"details": details
})
if (!toastVisible)
processQueue()
}
function showInfo(message) {
showToast(message, levelInfo)
function showInfo(message, details = "") {
showToast(message, levelInfo, details)
}
function showWarning(message) {
showToast(message, levelWarn)
function showWarning(message, details = "") {
showToast(message, levelWarn, details)
}
function showError(message) {
showToast(message, levelError)
function showError(message, details = "") {
showToast(message, levelError, details)
}
function hideToast() {
toastVisible = false
currentMessage = ""
currentDetails = ""
hasDetails = false
currentLevel = levelInfo
toastTimer.stop()
resetToastState()
if (toastQueue.length > 0)
processQueue()
}
@@ -54,10 +60,31 @@ Singleton {
const toast = toastQueue.shift()
currentMessage = toast.message
currentLevel = toast.level
currentDetails = toast.details || ""
hasDetails = currentDetails.length > 0
toastVisible = true
toastTimer.interval = toast.level
=== levelError ? 5000 : toast.level === levelWarn ? 4000 : 3000
toastTimer.start()
resetToastState()
if (toast.level === levelError && hasDetails) {
toastTimer.interval = 8000
toastTimer.start()
} else {
toastTimer.interval = toast.level === levelError ? 5000 : toast.level === levelWarn ? 4000 : 3000
toastTimer.start()
}
}
signal resetToastState
function stopTimer() {
toastTimer.stop()
}
function restartTimer() {
if (hasDetails && currentLevel === levelError) {
toastTimer.interval = 8000
toastTimer.restart()
}
}
function clearWallpaperError() {

View File

@@ -239,6 +239,7 @@ ShellRoot {
delegate: Toast {
modelData: item
visible: ToastService.toastVisible
}
}