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

fix loader patterns in settings

- fix matugen command
- fix focused window being wrong sometimes
This commit is contained in:
bbedward
2025-08-12 23:31:58 -04:00
parent 6e92df95e9
commit bbd23171cc
9 changed files with 2957 additions and 3105 deletions

View File

@@ -29,7 +29,6 @@ Singleton {
property bool gtkThemingEnabled: false property bool gtkThemingEnabled: false
property bool qtThemingEnabled: false property bool qtThemingEnabled: false
property bool systemThemeGenerationInProgress: false property bool systemThemeGenerationInProgress: false
property string matugenJson: ""
property var matugenColors: ({}) property var matugenColors: ({})
property bool extractionRequested: false property bool extractionRequested: false
property int colorUpdateTrigger: 0 property int colorUpdateTrigger: 0
@@ -141,51 +140,33 @@ Singleton {
Process { Process {
id: matugenProcess id: matugenProcess
command: ["matugen", "-v", "image", wallpaperPath, "--json", "hex"] command: ["matugen", "image", wallpaperPath, "--json", "hex"]
stdout: StdioCollector { stdout: StdioCollector {
id: matugenCollector id: matugenCollector
onStreamFinished: { onStreamFinished: {
const out = matugenCollector.text if (!matugenCollector.text) {
const startIndex = out.indexOf('{')
const endIndex = out.lastIndexOf('}')
let jsonStringOnly = ""
if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
jsonStringOnly = out.substring(startIndex, endIndex + 1)
}
if (!jsonStringOnly.length) {
ToastService.wallpaperErrorStatus = "error" ToastService.wallpaperErrorStatus = "error"
ToastService.showError("Wallpaper Processing Failed: Empty JSON extracted from matugen output.") ToastService.showError("Wallpaper Processing Failed: Empty JSON extracted from matugen output.")
return return
} }
try { try {
root.matugenJson = jsonStringOnly root.matugenColors = JSON.parse(matugenCollector.text)
root.matugenColors = JSON.parse(jsonStringOnly)
root.colorsUpdated() root.colorsUpdated()
generateAppConfigs() generateAppConfigs()
ToastService.clearWallpaperError() ToastService.clearWallpaperError()
} catch (e) { } catch (e) {
ToastService.wallpaperErrorStatus = "error" ToastService.wallpaperErrorStatus = "error"
const stderr = matugenErr.text ToastService.showError("Wallpaper processing failed (JSON parse error after extraction)")
const msg = "Wallpaper processing failed (JSON parse error after extraction)"
+ (stderr ? `: ${stderr}` : ` with output: ${jsonStringOnly}`)
ToastService.showError(msg)
} }
} }
} }
stderr: StdioCollector {
id: matugenErr
}
onExited: code => { onExited: code => {
if (code !== 0) { if (code !== 0) {
ToastService.wallpaperErrorStatus = "error" ToastService.wallpaperErrorStatus = "error"
const stderr = matugenErr.text ToastService.showError("Matugen command failed with exit code " + code)
const msg = "Matugen command failed with exit code " + code
+ (stderr ? `: ${stderr}` : ". No stderr output.")
ToastService.showError(msg)
} }
} }
} }

View File

@@ -121,16 +121,18 @@ DankModal {
color: "transparent" color: "transparent"
Loader { Loader {
id: personalizationLoader
anchors.fill: parent anchors.fill: parent
active: settingsTabBar.currentIndex === 0 active: settingsTabBar.currentIndex === 0
visible: active visible: active
asynchronous: false asynchronous: true
sourceComponent: Component { sourceComponent: Component {
PersonalizationTab {} PersonalizationTab {}
} }
} }
Loader { Loader {
id: timeWeatherLoader
anchors.fill: parent anchors.fill: parent
active: settingsTabBar.currentIndex === 1 active: settingsTabBar.currentIndex === 1
visible: active visible: active
@@ -141,6 +143,7 @@ DankModal {
} }
Loader { Loader {
id: widgetsLoader
anchors.fill: parent anchors.fill: parent
active: settingsTabBar.currentIndex === 2 active: settingsTabBar.currentIndex === 2
visible: active visible: active
@@ -151,6 +154,7 @@ DankModal {
} }
Loader { Loader {
id: launcherLoader
anchors.fill: parent anchors.fill: parent
active: settingsTabBar.currentIndex === 3 active: settingsTabBar.currentIndex === 3
visible: active visible: active
@@ -161,10 +165,11 @@ DankModal {
} }
Loader { Loader {
id: appearanceLoader
anchors.fill: parent anchors.fill: parent
active: settingsTabBar.currentIndex === 4 active: settingsTabBar.currentIndex === 4
visible: active visible: active
asynchronous: false asynchronous: true
sourceComponent: Component { sourceComponent: Component {
AppearanceTab {} AppearanceTab {}
} }

View File

@@ -175,5 +175,53 @@ Rectangle {
} }
} }
} }
Rectangle {
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
}
Item {
width: parent.width
height: 36
Row {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "notifications_active"
size: Theme.iconSizeSmall
color: SettingsData.notificationOverlayEnabled ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Column {
spacing: 2
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Notification Overlay"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
}
StyledText {
text: "Display all priorities over fullscreen apps"
font.pixelSize: Theme.fontSizeSmall - 1
color: Theme.surfaceVariantText
}
}
}
DankToggle {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.notificationOverlayEnabled
onToggled: (toggled) => SettingsData.setNotificationOverlayEnabled(toggled)
}
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -20,482 +20,453 @@ Item {
width: parent.width width: parent.width
spacing: Theme.spacingXL spacing: Theme.spacingXL
Loader { StyledRect {
width: parent.width width: parent.width
sourceComponent: appLauncherComponent height: appLauncherSection.implicitHeight + Theme.spacingL * 2
} radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Loader { Column {
width: parent.width id: appLauncherSection
sourceComponent: dockComponent
}
Loader { anchors.fill: parent
width: parent.width anchors.margins: Theme.spacingL
sourceComponent: recentlyUsedComponent spacing: Theme.spacingM
}
}
}
// App Launcher Component DankToggle {
Component { width: parent.width
id: appLauncherComponent text: "Use OS Logo"
description: "Display operating system logo instead of apps icon"
checked: SettingsData.useOSLogo
onToggled: checked => {
return SettingsData.setUseOSLogo(checked)
}
}
StyledRect { Row {
width: parent.width width: parent.width - Theme.spacingL
height: appLauncherSection.implicitHeight + Theme.spacingL * 2 spacing: Theme.spacingL
radius: Theme.cornerRadius visible: SettingsData.useOSLogo
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, opacity: visible ? 1 : 0
Theme.surfaceVariant.b, 0.3) anchors.left: parent.left
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, anchors.leftMargin: Theme.spacingL
Theme.outline.b, 0.2)
border.width: 1
Column { Column {
id: appLauncherSection width: 120
spacing: Theme.spacingS
anchors.fill: parent StyledText {
anchors.margins: Theme.spacingL text: "Color Override"
spacing: Theme.spacingM font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankToggle { DankTextField {
width: parent.width width: 100
text: "Use OS Logo" height: 28
description: "Display operating system logo instead of apps icon" placeholderText: "#ffffff"
checked: SettingsData.useOSLogo text: SettingsData.osLogoColorOverride
onToggled: checked => { maximumLength: 7
return SettingsData.setUseOSLogo(checked) font.pixelSize: Theme.fontSizeSmall
} topPadding: Theme.spacingXS
} bottomPadding: Theme.spacingXS
onEditingFinished: {
Row { var color = text.trim()
width: parent.width - Theme.spacingL if (color === "" || /^#[0-9A-Fa-f]{6}$/.test(color))
spacing: Theme.spacingL SettingsData.setOSLogoColorOverride(color)
visible: SettingsData.useOSLogo else
opacity: visible ? 1 : 0 text = SettingsData.osLogoColorOverride
anchors.left: parent.left }
anchors.leftMargin: Theme.spacingL }
Column {
width: 120
spacing: Theme.spacingS
StyledText {
text: "Color Override"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
} }
DankTextField { Column {
width: 100 width: 120
height: 28 spacing: Theme.spacingS
placeholderText: "#ffffff"
text: SettingsData.osLogoColorOverride StyledText {
maximumLength: 7 text: "Brightness"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
topPadding: Theme.spacingXS color: Theme.surfaceText
bottomPadding: Theme.spacingXS font.weight: Font.Medium
onEditingFinished: { }
var color = text.trim()
if (color === "" || /^#[0-9A-Fa-f]{6}$/.test(color)) DankSlider {
SettingsData.setOSLogoColorOverride(color) width: 100
else height: 20
text = SettingsData.osLogoColorOverride minimum: 0
maximum: 100
value: Math.round(SettingsData.osLogoBrightness * 100)
unit: "%"
showValue: true
onSliderValueChanged: newValue => {
SettingsData.setOSLogoBrightness(
newValue / 100)
}
}
}
Column {
width: 120
spacing: Theme.spacingS
StyledText {
text: "Contrast"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: 100
height: 20
minimum: 0
maximum: 200
value: Math.round(SettingsData.osLogoContrast * 100)
unit: "%"
showValue: true
onSliderValueChanged: newValue => {
SettingsData.setOSLogoContrast(
newValue / 100)
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
StyledRect {
width: parent.width
height: dockSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Column {
id: dockSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "dock_to_bottom"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Dock"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Show Dock"
description: "Display a dock at the bottom of the screen with pinned and running applications"
checked: SettingsData.showDock
onToggled: checked => {
SettingsData.setShowDock(checked)
}
}
DankToggle {
width: parent.width
text: "Auto-hide Dock"
description: "Hide the dock when not in use and reveal it when hovering near the bottom of the screen"
checked: SettingsData.dockAutoHide
visible: SettingsData.showDock
opacity: visible ? 1 : 0
onToggled: checked => {
SettingsData.setDockAutoHide(checked)
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
} }
} }
} }
Column { Column {
width: 120 width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
visible: SettingsData.showDock
opacity: visible ? 1 : 0
StyledText { StyledText {
text: "Brightness" text: "Dock Transparency"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
} }
DankSlider { DankSlider {
width: 100 width: parent.width
height: 20 height: 24
value: Math.round(SettingsData.dockTransparency * 100)
minimum: 0 minimum: 0
maximum: 100 maximum: 100
value: Math.round(SettingsData.osLogoBrightness * 100) unit: ""
unit: "%"
showValue: true showValue: true
onSliderValueChanged: newValue => { onSliderValueChanged: newValue => {
SettingsData.setOSLogoBrightness( SettingsData.setDockTransparency(
newValue / 100) newValue / 100)
} }
} }
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
StyledRect {
width: parent.width
height: recentlyUsedSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Column {
id: recentlyUsedSection
property var rankedAppsModel: {
var apps = []
for (var appId in (AppUsageHistoryData.appUsageRanking || {})) {
var appData = (AppUsageHistoryData.appUsageRanking || {})[appId]
apps.push({
"id": appId,
"name": appData.name,
"exec": appData.exec,
"icon": appData.icon,
"comment": appData.comment,
"usageCount": appData.usageCount,
"lastUsed": appData.lastUsed
})
}
apps.sort(function (a, b) {
if (a.usageCount !== b.usageCount)
return b.usageCount - a.usageCount
return a.name.localeCompare(b.name)
})
return apps.slice(0, 20)
}
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "history"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Recently Used Apps"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - parent.children[0].width - parent.children[1].width
- clearAllButton.width - Theme.spacingM * 3
height: 1
}
DankActionButton {
id: clearAllButton
iconName: "delete_sweep"
iconSize: Theme.iconSize - 2
iconColor: Theme.error
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g,
Theme.error.b, 0.12)
anchors.verticalCenter: parent.verticalCenter
onClicked: {
AppUsageHistoryData.appUsageRanking = {}
SettingsData.saveSettings()
}
}
}
StyledText {
width: parent.width
text: "Apps are ordered by usage frequency, then last used, then alphabetically."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
} }
Column { Column {
width: 120 id: rankedAppsList
width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
StyledText { Repeater {
text: "Contrast" model: recentlyUsedSection.rankedAppsModel
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider { delegate: Rectangle {
width: 100 width: rankedAppsList.width
height: 20 height: 48
minimum: 0 radius: Theme.cornerRadius
maximum: 200 color: Qt.rgba(Theme.surfaceContainer.r,
value: Math.round(SettingsData.osLogoContrast * 100) Theme.surfaceContainer.g,
unit: "%" Theme.surfaceContainer.b, 0.3)
showValue: true border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
onSliderValueChanged: newValue => { Theme.outline.b, 0.1)
SettingsData.setOSLogoContrast( border.width: 1
newValue / 100)
}
}
}
Behavior on opacity { Row {
NumberAnimation { anchors.left: parent.left
duration: Theme.mediumDuration anchors.leftMargin: Theme.spacingM
easing.type: Theme.emphasizedEasing
}
}
}
}
}
}
// Dock Component
Component {
id: dockComponent
StyledRect {
width: parent.width
height: dockSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Column {
id: dockSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "dock_to_bottom"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Dock"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Show Dock"
description: "Display a dock at the bottom of the screen with pinned and running applications"
checked: SettingsData.showDock
onToggled: checked => {
SettingsData.setShowDock(checked)
}
}
DankToggle {
width: parent.width
text: "Auto-hide Dock"
description: "Hide the dock when not in use and reveal it when hovering near the bottom of the screen"
checked: SettingsData.dockAutoHide
visible: SettingsData.showDock
opacity: visible ? 1 : 0
onToggled: checked => {
SettingsData.setDockAutoHide(checked)
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
visible: SettingsData.showDock
opacity: visible ? 1 : 0
StyledText {
text: "Dock Transparency"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankSlider {
width: parent.width
height: 24
value: Math.round(SettingsData.dockTransparency * 100)
minimum: 0
maximum: 100
unit: ""
showValue: true
onSliderValueChanged: newValue => {
SettingsData.setDockTransparency(
newValue / 100)
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
}
// Recently Used Apps Component
Component {
id: recentlyUsedComponent
StyledRect {
width: parent.width
height: recentlyUsedSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Column {
id: recentlyUsedSection
property var rankedAppsModel: {
var apps = []
for (var appId in (AppUsageHistoryData.appUsageRanking || {})) {
var appData = (AppUsageHistoryData.appUsageRanking || {})[appId]
apps.push({
"id": appId,
"name": appData.name,
"exec": appData.exec,
"icon": appData.icon,
"comment": appData.comment,
"usageCount": appData.usageCount,
"lastUsed": appData.lastUsed
})
}
apps.sort(function (a, b) {
if (a.usageCount !== b.usageCount)
return b.usageCount - a.usageCount
return a.name.localeCompare(b.name)
})
return apps.slice(0, 20)
}
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "history"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Recently Used Apps"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - parent.children[0].width - parent.children[1].width
- clearAllButton.width - Theme.spacingM * 3
height: 1
}
DankActionButton {
id: clearAllButton
iconName: "delete_sweep"
iconSize: Theme.iconSize - 2
iconColor: Theme.error
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g,
Theme.error.b, 0.12)
anchors.verticalCenter: parent.verticalCenter
onClicked: {
AppUsageHistoryData.appUsageRanking = {}
SettingsData.saveSettings()
}
}
}
StyledText {
width: parent.width
text: "Apps are ordered by usage frequency, then last used, then alphabetically."
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
}
Column {
id: rankedAppsList
width: parent.width
spacing: Theme.spacingS
Repeater {
model: recentlyUsedSection.rankedAppsModel
delegate: Rectangle {
width: rankedAppsList.width
height: 48
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r,
Theme.surfaceContainer.g,
Theme.surfaceContainer.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.1)
border.width: 1
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
StyledText {
text: (index + 1).toString()
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.primary
width: 20
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} spacing: Theme.spacingM
Image {
width: 24
height: 24
source: modelData.icon ? "image://icon/" + modelData.icon : "image://icon/application-x-executable"
sourceSize.width: 24
sourceSize.height: 24
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
onStatusChanged: {
if (status === Image.Error)
source = "image://icon/application-x-executable"
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
StyledText { StyledText {
text: modelData.name || "Unknown App" text: (index + 1).toString()
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: {
if (!modelData.lastUsed)
return "Never used"
var date = new Date(modelData.lastUsed)
var now = new Date()
var diffMs = now - date
var diffMins = Math.floor(diffMs / (1000 * 60))
var diffHours = Math.floor(diffMs / (1000 * 60 * 60))
var diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))
if (diffMins < 1)
return "Last launched just now"
if (diffMins < 60)
return "Last launched " + diffMins + " minute"
+ (diffMins === 1 ? "" : "s") + " ago"
if (diffHours < 24)
return "Last launched " + diffHours + " hour"
+ (diffHours === 1 ? "" : "s") + " ago"
if (diffDays < 7)
return "Last launched " + diffDays + " day"
+ (diffDays === 1 ? "" : "s") + " ago"
return "Last launched " + date.toLocaleDateString()
}
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText font.weight: Font.Medium
color: Theme.primary
width: 20
anchors.verticalCenter: parent.verticalCenter
}
Image {
width: 24
height: 24
source: modelData.icon ? "image://icon/" + modelData.icon : "image://icon/application-x-executable"
sourceSize.width: 24
sourceSize.height: 24
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
onStatusChanged: {
if (status === Image.Error)
source = "image://icon/application-x-executable"
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
StyledText {
text: modelData.name || "Unknown App"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: {
if (!modelData.lastUsed)
return "Never used"
var date = new Date(modelData.lastUsed)
var now = new Date()
var diffMs = now - date
var diffMins = Math.floor(diffMs / (1000 * 60))
var diffHours = Math.floor(diffMs / (1000 * 60 * 60))
var diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24))
if (diffMins < 1)
return "Last launched just now"
if (diffMins < 60)
return "Last launched " + diffMins + " minute"
+ (diffMins === 1 ? "" : "s") + " ago"
if (diffHours < 24)
return "Last launched " + diffHours + " hour"
+ (diffHours === 1 ? "" : "s") + " ago"
if (diffDays < 7)
return "Last launched " + diffDays + " day"
+ (diffDays === 1 ? "" : "s") + " ago"
return "Last launched " + date.toLocaleDateString()
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
}
DankActionButton {
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
circular: true
iconName: "close"
iconSize: 16
iconColor: Theme.error
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g,
Theme.error.b, 0.12)
onClicked: {
var currentRanking = Object.assign(
{}, AppUsageHistoryData.appUsageRanking || {})
delete currentRanking[modelData.id]
AppUsageHistoryData.appUsageRanking = currentRanking
SettingsData.saveSettings()
} }
} }
} }
DankActionButton {
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
circular: true
iconName: "close"
iconSize: 16
iconColor: Theme.error
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g,
Theme.error.b, 0.12)
onClicked: {
var currentRanking = Object.assign(
{}, AppUsageHistoryData.appUsageRanking || {})
delete currentRanking[modelData.id]
AppUsageHistoryData.appUsageRanking = currentRanking
SettingsData.saveSettings()
}
}
} }
}
StyledText { StyledText {
width: parent.width width: parent.width
text: recentlyUsedSection.rankedAppsModel.length text: recentlyUsedSection.rankedAppsModel.length
=== 0 ? "No apps have been launched yet." : "" === 0 ? "No apps have been launched yet." : ""
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
visible: recentlyUsedSection.rankedAppsModel.length === 0 visible: recentlyUsedSection.rankedAppsModel.length === 0
}
} }
} }
} }
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -20,438 +20,403 @@ Item {
width: parent.width width: parent.width
spacing: Theme.spacingXL spacing: Theme.spacingXL
Loader { // Time Format
StyledRect {
width: parent.width width: parent.width
sourceComponent: timeComponent height: timeSection.implicitHeight + Theme.spacingL * 2
} radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
Loader { border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
width: parent.width border.width: 1
sourceComponent: weatherComponent
}
}
}
// Time Format Component
Component {
id: timeComponent
StyledRect {
width: parent.width
height: timeSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: timeSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "schedule"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Time Format"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "24-Hour Format"
description: "Use 24-hour time format instead of 12-hour AM/PM"
checked: SettingsData.use24HourClock
onToggled: (checked) => {
return SettingsData.setClockFormat(checked);
}
}
Column { Column {
width: parent.width id: timeSection
spacing: Theme.spacingS
StyledText { anchors.fill: parent
text: "Date Format" anchors.margins: Theme.spacingL
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
DankDropdown {
width: parent.width
height: 50
text: "Top Bar Format"
description: "Preview: " + Qt.formatDate(new Date(), SettingsData.clockDateFormat)
currentValue: {
// Find matching preset or show "Custom"
const presets = [{
"format": "ddd d",
"label": "Day Date"
}, {
"format": "ddd MMM d",
"label": "Day Month Date"
}, {
"format": "MMM d",
"label": "Month Date"
}, {
"format": "M/d",
"label": "Numeric (M/D)"
}, {
"format": "d/M",
"label": "Numeric (D/M)"
}, {
"format": "ddd d MMM yyyy",
"label": "Full with Year"
}, {
"format": "yyyy-MM-dd",
"label": "ISO Date"
}, {
"format": "dddd, MMMM d",
"label": "Full Day & Month"
}];
const match = presets.find((p) => {
return p.format === SettingsData.clockDateFormat;
});
return match ? match.label : "Custom: " + SettingsData.clockDateFormat;
}
options: ["Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
onValueChanged: (value) => {
const formatMap = {
"Day Date": "ddd d",
"Day Month Date": "ddd MMM d",
"Month Date": "MMM d",
"Numeric (M/D)": "M/d",
"Numeric (D/M)": "d/M",
"Full with Year": "ddd d MMM yyyy",
"ISO Date": "yyyy-MM-dd",
"Full Day & Month": "dddd, MMMM d"
};
if (value === "Custom...") {
customFormatInput.visible = true;
} else {
customFormatInput.visible = false;
SettingsData.setClockDateFormat(formatMap[value]);
}
}
}
DankDropdown {
width: parent.width
height: 50
text: "Lock Screen Format"
description: "Preview: " + Qt.formatDate(new Date(), SettingsData.lockDateFormat)
currentValue: {
// Find matching preset or show "Custom"
const presets = [{
"format": "ddd d",
"label": "Day Date"
}, {
"format": "ddd MMM d",
"label": "Day Month Date"
}, {
"format": "MMM d",
"label": "Month Date"
}, {
"format": "M/d",
"label": "Numeric (M/D)"
}, {
"format": "d/M",
"label": "Numeric (D/M)"
}, {
"format": "ddd d MMM yyyy",
"label": "Full with Year"
}, {
"format": "yyyy-MM-dd",
"label": "ISO Date"
}, {
"format": "dddd, MMMM d",
"label": "Full Day & Month"
}];
const match = presets.find((p) => {
return p.format === SettingsData.lockDateFormat;
});
return match ? match.label : "Custom: " + SettingsData.lockDateFormat;
}
options: ["Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
onValueChanged: (value) => {
const formatMap = {
"Day Date": "ddd d",
"Day Month Date": "ddd MMM d",
"Month Date": "MMM d",
"Numeric (M/D)": "M/d",
"Numeric (D/M)": "d/M",
"Full with Year": "ddd d MMM yyyy",
"ISO Date": "yyyy-MM-dd",
"Full Day & Month": "dddd, MMMM d"
};
if (value === "Custom...") {
customLockFormatInput.visible = true;
} else {
customLockFormatInput.visible = false;
SettingsData.setLockDateFormat(formatMap[value]);
}
}
}
DankTextField {
id: customFormatInput
width: parent.width
visible: false
placeholderText: "Enter custom top bar format (e.g., ddd MMM d)"
text: SettingsData.clockDateFormat
onTextChanged: {
if (visible && text)
SettingsData.setClockDateFormat(text);
}
}
DankTextField {
id: customLockFormatInput
width: parent.width
visible: false
placeholderText: "Enter custom lock screen format (e.g., dddd, MMMM d)"
text: SettingsData.lockDateFormat
onTextChanged: {
if (visible && text)
SettingsData.setLockDateFormat(text);
}
}
Rectangle {
width: parent.width
height: formatHelp.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
border.width: 1
Column {
id: formatHelp
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingXS
StyledText {
text: "Format Legend"
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
font.weight: Font.Medium
}
Row {
spacing: Theme.spacingL
Column {
spacing: 2
StyledText {
text: "• d - Day (1-31)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• dd - Day (01-31)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• ddd - Day name (Mon)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• dddd - Day name (Monday)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Column {
spacing: 2
StyledText {
text: "• M - Month (1-12)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MM - Month (01-12)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MMM - Month (Jan)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MMMM - Month (January)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Column {
spacing: 2
StyledText {
text: "• yy - Year (24)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• yyyy - Year (2024)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
}
}
}
}
}
}
}
// Weather Component
Component {
id: weatherComponent
StyledRect {
width: parent.width
height: weatherSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: weatherSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { Row {
name: "cloud"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Weather"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Enable Weather"
description: "Show weather information in top bar and centcom center"
checked: SettingsData.weatherEnabled
onToggled: (checked) => {
return SettingsData.setWeatherEnabled(checked);
}
}
DankToggle {
width: parent.width
text: "Fahrenheit"
description: "Use Fahrenheit instead of Celsius for temperature"
checked: SettingsData.useFahrenheit
enabled: SettingsData.weatherEnabled
onToggled: (checked) => {
return SettingsData.setTemperatureUnit(checked);
}
}
DankToggle {
width: parent.width
text: "Auto Location"
description: "Allow wttr.in to determine location based on IP address"
checked: SettingsData.useAutoLocation
enabled: SettingsData.weatherEnabled
onToggled: (checked) => {
return SettingsData.setAutoLocation(checked);
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
visible: !SettingsData.useAutoLocation && SettingsData.weatherEnabled
StyledText {
text: "Location"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
DankLocationSearch {
width: parent.width width: parent.width
currentLocation: SettingsData.weatherLocation spacing: Theme.spacingM
placeholderText: "New York, NY"
onLocationSelected: (displayName, coordinates) => { DankIcon {
SettingsData.setWeatherLocation(displayName, coordinates); name: "schedule"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Time Format"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
} }
} }
} DankToggle {
width: parent.width
text: "24-Hour Format"
description: "Use 24-hour time format instead of 12-hour AM/PM"
checked: SettingsData.use24HourClock
onToggled: (checked) => {
return SettingsData.setClockFormat(checked);
}
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: "Date Format"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
DankDropdown {
width: parent.width
height: 50
text: "Top Bar Format"
description: "Preview: " + Qt.formatDate(new Date(), SettingsData.clockDateFormat)
currentValue: {
// Find matching preset or show "Custom"
const presets = [{
"format": "ddd d",
"label": "Day Date"
}, {
"format": "ddd MMM d",
"label": "Day Month Date"
}, {
"format": "MMM d",
"label": "Month Date"
}, {
"format": "M/d",
"label": "Numeric (M/D)"
}, {
"format": "d/M",
"label": "Numeric (D/M)"
}, {
"format": "ddd d MMM yyyy",
"label": "Full with Year"
}, {
"format": "yyyy-MM-dd",
"label": "ISO Date"
}, {
"format": "dddd, MMMM d",
"label": "Full Day & Month"
}];
const match = presets.find((p) => {
return p.format === SettingsData.clockDateFormat;
});
return match ? match.label : "Custom: " + SettingsData.clockDateFormat;
}
options: ["Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
onValueChanged: (value) => {
const formatMap = {
"Day Date": "ddd d",
"Day Month Date": "ddd MMM d",
"Month Date": "MMM d",
"Numeric (M/D)": "M/d",
"Numeric (D/M)": "d/M",
"Full with Year": "ddd d MMM yyyy",
"ISO Date": "yyyy-MM-dd",
"Full Day & Month": "dddd, MMMM d"
};
if (value === "Custom...") {
customFormatInput.visible = true;
} else {
customFormatInput.visible = false;
SettingsData.setClockDateFormat(formatMap[value]);
}
}
}
DankDropdown {
width: parent.width
height: 50
text: "Lock Screen Format"
description: "Preview: " + Qt.formatDate(new Date(), SettingsData.lockDateFormat)
currentValue: {
// Find matching preset or show "Custom"
const presets = [{
"format": "ddd d",
"label": "Day Date"
}, {
"format": "ddd MMM d",
"label": "Day Month Date"
}, {
"format": "MMM d",
"label": "Month Date"
}, {
"format": "M/d",
"label": "Numeric (M/D)"
}, {
"format": "d/M",
"label": "Numeric (D/M)"
}, {
"format": "ddd d MMM yyyy",
"label": "Full with Year"
}, {
"format": "yyyy-MM-dd",
"label": "ISO Date"
}, {
"format": "dddd, MMMM d",
"label": "Full Day & Month"
}];
const match = presets.find((p) => {
return p.format === SettingsData.lockDateFormat;
});
return match ? match.label : "Custom: " + SettingsData.lockDateFormat;
}
options: ["Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
onValueChanged: (value) => {
const formatMap = {
"Day Date": "ddd d",
"Day Month Date": "ddd MMM d",
"Month Date": "MMM d",
"Numeric (M/D)": "M/d",
"Numeric (D/M)": "d/M",
"Full with Year": "ddd d MMM yyyy",
"ISO Date": "yyyy-MM-dd",
"Full Day & Month": "dddd, MMMM d"
};
if (value === "Custom...") {
customLockFormatInput.visible = true;
} else {
customLockFormatInput.visible = false;
SettingsData.setLockDateFormat(formatMap[value]);
}
}
}
DankTextField {
id: customFormatInput
width: parent.width
visible: false
placeholderText: "Enter custom top bar format (e.g., ddd MMM d)"
text: SettingsData.clockDateFormat
onTextChanged: {
if (visible && text)
SettingsData.setClockDateFormat(text);
}
}
DankTextField {
id: customLockFormatInput
width: parent.width
visible: false
placeholderText: "Enter custom lock screen format (e.g., dddd, MMMM d)"
text: SettingsData.lockDateFormat
onTextChanged: {
if (visible && text)
SettingsData.setLockDateFormat(text);
}
}
Rectangle {
width: parent.width
height: formatHelp.implicitHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
border.width: 1
Column {
id: formatHelp
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingXS
StyledText {
text: "Format Legend"
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
font.weight: Font.Medium
}
Row {
spacing: Theme.spacingL
Column {
spacing: 2
StyledText {
text: "• d - Day (1-31)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• dd - Day (01-31)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• ddd - Day name (Mon)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• dddd - Day name (Monday)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Column {
spacing: 2
StyledText {
text: "• M - Month (1-12)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MM - Month (01-12)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MMM - Month (Jan)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• MMMM - Month (January)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Column {
spacing: 2
StyledText {
text: "• yy - Year (24)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: "• yyyy - Year (2024)"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
}
}
}
}
}
}
// Weather
StyledRect {
width: parent.width
height: weatherSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Column {
id: weatherSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "cloud"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Weather"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Enable Weather"
description: "Show weather information in top bar and centcom center"
checked: SettingsData.weatherEnabled
onToggled: (checked) => {
return SettingsData.setWeatherEnabled(checked);
}
}
DankToggle {
width: parent.width
text: "Fahrenheit"
description: "Use Fahrenheit instead of Celsius for temperature"
checked: SettingsData.useFahrenheit
enabled: SettingsData.weatherEnabled
onToggled: (checked) => {
return SettingsData.setTemperatureUnit(checked);
}
}
DankToggle {
width: parent.width
text: "Auto Location"
description: "Allow wttr.in to determine location based on IP address"
checked: SettingsData.useAutoLocation
enabled: SettingsData.weatherEnabled
onToggled: (checked) => {
return SettingsData.setAutoLocation(checked);
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
visible: !SettingsData.useAutoLocation && SettingsData.weatherEnabled
StyledText {
text: "Location"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
DankLocationSearch {
width: parent.width
currentLocation: SettingsData.weatherLocation
placeholderText: "New York, NY"
onLocationSelected: (displayName, coordinates) => {
SettingsData.setWeatherLocation(displayName, coordinates);
}
}
}
}
} }
} }
} }
} }

View File

@@ -437,499 +437,449 @@ Item {
width: parent.width width: parent.width
spacing: Theme.spacingXL spacing: Theme.spacingXL
Loader { Row {
width: parent.width width: parent.width
sourceComponent: headerComponent
}
Loader {
width: parent.width
sourceComponent: messageComponent
}
Loader {
width: parent.width
sourceComponent: sectionsComponent
}
Loader {
width: parent.width
sourceComponent: workspaceComponent
}
Loader {
width: parent.width
sourceComponent: workspaceIconsComponent
visible: SettingsData.hasNamedWorkspaces()
}
}
}
// Header Component
Component {
id: headerComponent
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "widgets"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Top Bar Widget Management"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - 400
height: 1
}
Rectangle {
width: 80
height: 28
radius: Theme.cornerRadius
color: resetArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariant
anchors.verticalCenter: parent.verticalCenter
border.width: 1
border.color: resetArea.containsMouse ? Theme.outline : Qt.rgba(
Theme.outline.r,
Theme.outline.g,
Theme.outline.b, 0.5)
Row {
anchors.centerIn: parent
spacing: Theme.spacingXS
DankIcon {
name: "refresh"
size: 14
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Reset"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: resetArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
SettingsData.setTopBarLeftWidgets(defaultLeftWidgets)
SettingsData.setTopBarCenterWidgets(defaultCenterWidgets)
SettingsData.setTopBarRightWidgets(defaultRightWidgets)
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on border.color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
// Message Component
Component {
id: messageComponent
Rectangle {
width: parent.width
height: messageText.contentHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
StyledText {
id: messageText
anchors.centerIn: parent
text: "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely."
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
width: parent.width - Theme.spacingM * 2
wrapMode: Text.WordWrap
}
}
}
// Sections Component
Component {
id: sectionsComponent
Column {
width: parent.width
spacing: Theme.spacingL
WidgetsTabSection {
width: parent.width
title: "Left Section"
titleIcon: "format_align_left"
sectionId: "left"
allWidgets: widgetsTab.baseWidgetDefinitions
items: widgetsTab.getItemsForSection("left")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
widgetsTab.handleItemEnabledChanged(sectionId,
itemId,
enabled)
}
onItemOrderChanged: newOrder => {
widgetsTab.handleItemOrderChanged("left",
newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets = widgetsTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
widgetsTab.removeWidgetFromSection(sectionId,
widgetIndex)
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
widgetsTab.handleSpacerSizeChanged(sectionId,
itemId,
newSize)
}
onCompactModeChanged: (widgetId, value) => {
if (widgetId === "clock") {
SettingsData.setClockCompactMode(value)
} else if (widgetId === "music") {
SettingsData.setMediaSize(value)
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
widgetsTab.handleGpuSelectionChanged(
sectionId, widgetIndex, selectedIndex)
}
}
WidgetsTabSection {
width: parent.width
title: "Center Section"
titleIcon: "format_align_center"
sectionId: "center"
allWidgets: widgetsTab.baseWidgetDefinitions
items: widgetsTab.getItemsForSection("center")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
widgetsTab.handleItemEnabledChanged(sectionId,
itemId,
enabled)
}
onItemOrderChanged: newOrder => {
widgetsTab.handleItemOrderChanged("center",
newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets = widgetsTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
widgetsTab.removeWidgetFromSection(sectionId,
widgetIndex)
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
widgetsTab.handleSpacerSizeChanged(sectionId,
itemId,
newSize)
}
onCompactModeChanged: (widgetId, value) => {
if (widgetId === "clock") {
SettingsData.setClockCompactMode(value)
} else if (widgetId === "music") {
SettingsData.setMediaSize(value)
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
widgetsTab.handleGpuSelectionChanged(
sectionId, widgetIndex, selectedIndex)
}
}
WidgetsTabSection {
width: parent.width
title: "Right Section"
titleIcon: "format_align_right"
sectionId: "right"
allWidgets: widgetsTab.baseWidgetDefinitions
items: widgetsTab.getItemsForSection("right")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
widgetsTab.handleItemEnabledChanged(sectionId,
itemId,
enabled)
}
onItemOrderChanged: newOrder => {
widgetsTab.handleItemOrderChanged("right",
newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets = widgetsTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
widgetsTab.removeWidgetFromSection(sectionId,
widgetIndex)
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
widgetsTab.handleSpacerSizeChanged(sectionId,
itemId,
newSize)
}
onCompactModeChanged: (widgetId, value) => {
if (widgetId === "clock") {
SettingsData.setClockCompactMode(value)
} else if (widgetId === "music") {
SettingsData.setMediaSize(value)
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
widgetsTab.handleGpuSelectionChanged(
sectionId, widgetIndex, selectedIndex)
}
}
}
}
// Workspace Settings Component
Component {
id: workspaceComponent
StyledRect {
width: parent.width
height: workspaceSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Column {
id: workspaceSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM spacing: Theme.spacingM
Row { DankIcon {
width: parent.width name: "widgets"
spacing: Theme.spacingM size: Theme.iconSize
color: Theme.primary
DankIcon { anchors.verticalCenter: parent.verticalCenter
name: "view_module"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Workspace Settings"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Workspace Index Numbers"
description: "Show workspace index numbers in the top bar workspace switcher"
checked: SettingsData.showWorkspaceIndex
onToggled: checked => {
return SettingsData.setShowWorkspaceIndex(checked)
}
}
DankToggle {
width: parent.width
text: "Workspace Padding"
description: "Always show a minimum of 3 workspaces, even if fewer are available"
checked: SettingsData.showWorkspacePadding
onToggled: checked => {
return SettingsData.setShowWorkspacePadding(checked)
}
}
}
}
}
// Workspace Icons Component
Component {
id: workspaceIconsComponent
StyledRect {
width: parent.width
height: workspaceIconsSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Column {
id: workspaceIconsSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "label"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Named Workspace Icons"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
} }
StyledText { StyledText {
width: parent.width text: "Top Bar Widget Management"
text: "Configure icons for named workspaces. Icons take priority over numbers when both are enabled." font.pixelSize: Theme.fontSizeLarge
font.pixelSize: Theme.fontSizeSmall font.weight: Font.Medium
color: Theme.outline color: Theme.surfaceText
wrapMode: Text.WordWrap anchors.verticalCenter: parent.verticalCenter
} }
Repeater { Item {
model: SettingsData.getNamedWorkspaces() width: parent.width - 400
height: 1
}
Rectangle { Rectangle {
width: parent.width width: 80
height: workspaceIconRow.implicitHeight + Theme.spacingM height: 28
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, color: resetArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariant
Theme.surfaceContainer.b, 0.5) anchors.verticalCenter: parent.verticalCenter
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, border.width: 1
Theme.outline.b, 0.3) border.color: resetArea.containsMouse ? Theme.outline : Qt.rgba(
border.width: 1 Theme.outline.r,
Theme.outline.g,
Theme.outline.b, 0.5)
Row { Row {
id: workspaceIconRow anchors.centerIn: parent
spacing: Theme.spacingXS
anchors.left: parent.left DankIcon {
anchors.right: parent.right name: "refresh"
size: 14
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Theme.spacingM }
anchors.rightMargin: Theme.spacingM
spacing: Theme.spacingM
StyledText { StyledText {
text: "\"" + modelData + "\"" text: "Reset"
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: resetArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
SettingsData.setTopBarLeftWidgets(defaultLeftWidgets)
SettingsData.setTopBarCenterWidgets(defaultCenterWidgets)
SettingsData.setTopBarRightWidgets(defaultRightWidgets)
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on border.color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
Rectangle {
width: parent.width
height: messageText.contentHeight + Theme.spacingM * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
StyledText {
id: messageText
anchors.centerIn: parent
text: "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely."
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
width: parent.width - Theme.spacingM * 2
wrapMode: Text.WordWrap
}
}
Column {
width: parent.width
spacing: Theme.spacingL
WidgetsTabSection {
width: parent.width
title: "Left Section"
titleIcon: "format_align_left"
sectionId: "left"
allWidgets: widgetsTab.baseWidgetDefinitions
items: widgetsTab.getItemsForSection("left")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
widgetsTab.handleItemEnabledChanged(sectionId,
itemId,
enabled)
}
onItemOrderChanged: newOrder => {
widgetsTab.handleItemOrderChanged("left",
newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets = widgetsTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
widgetsTab.removeWidgetFromSection(sectionId,
widgetIndex)
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
widgetsTab.handleSpacerSizeChanged(sectionId,
itemId,
newSize)
}
onCompactModeChanged: (widgetId, value) => {
if (widgetId === "clock") {
SettingsData.setClockCompactMode(value)
} else if (widgetId === "music") {
SettingsData.setMediaSize(value)
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
widgetsTab.handleGpuSelectionChanged(
sectionId, widgetIndex, selectedIndex)
}
}
WidgetsTabSection {
width: parent.width
title: "Center Section"
titleIcon: "format_align_center"
sectionId: "center"
allWidgets: widgetsTab.baseWidgetDefinitions
items: widgetsTab.getItemsForSection("center")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
widgetsTab.handleItemEnabledChanged(sectionId,
itemId,
enabled)
}
onItemOrderChanged: newOrder => {
widgetsTab.handleItemOrderChanged("center",
newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets = widgetsTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
widgetsTab.removeWidgetFromSection(sectionId,
widgetIndex)
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
widgetsTab.handleSpacerSizeChanged(sectionId,
itemId,
newSize)
}
onCompactModeChanged: (widgetId, value) => {
if (widgetId === "clock") {
SettingsData.setClockCompactMode(value)
} else if (widgetId === "music") {
SettingsData.setMediaSize(value)
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
widgetsTab.handleGpuSelectionChanged(
sectionId, widgetIndex, selectedIndex)
}
}
WidgetsTabSection {
width: parent.width
title: "Right Section"
titleIcon: "format_align_right"
sectionId: "right"
allWidgets: widgetsTab.baseWidgetDefinitions
items: widgetsTab.getItemsForSection("right")
onItemEnabledChanged: (sectionId, itemId, enabled) => {
widgetsTab.handleItemEnabledChanged(sectionId,
itemId,
enabled)
}
onItemOrderChanged: newOrder => {
widgetsTab.handleItemOrderChanged("right",
newOrder)
}
onAddWidget: sectionId => {
widgetSelectionPopup.allWidgets = widgetsTab.baseWidgetDefinitions
widgetSelectionPopup.targetSection = sectionId
widgetSelectionPopup.safeOpen()
}
onRemoveWidget: (sectionId, widgetIndex) => {
widgetsTab.removeWidgetFromSection(sectionId,
widgetIndex)
}
onSpacerSizeChanged: (sectionId, itemId, newSize) => {
widgetsTab.handleSpacerSizeChanged(sectionId,
itemId,
newSize)
}
onCompactModeChanged: (widgetId, value) => {
if (widgetId === "clock") {
SettingsData.setClockCompactMode(value)
} else if (widgetId === "music") {
SettingsData.setMediaSize(value)
}
}
onGpuSelectionChanged: (sectionId, widgetIndex, selectedIndex) => {
widgetsTab.handleGpuSelectionChanged(
sectionId, widgetIndex, selectedIndex)
}
}
}
StyledRect {
width: parent.width
height: workspaceSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
Column {
id: workspaceSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "view_module"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Workspace Settings"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
width: parent.width
text: "Workspace Index Numbers"
description: "Show workspace index numbers in the top bar workspace switcher"
checked: SettingsData.showWorkspaceIndex
onToggled: checked => {
return SettingsData.setShowWorkspaceIndex(checked)
}
}
DankToggle {
width: parent.width
text: "Workspace Padding"
description: "Always show a minimum of 3 workspaces, even if fewer are available"
checked: SettingsData.showWorkspacePadding
onToggled: checked => {
return SettingsData.setShowWorkspacePadding(checked)
}
}
}
}
StyledRect {
width: parent.width
height: workspaceIconsSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 1
visible: SettingsData.hasNamedWorkspaces()
Column {
id: workspaceIconsSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "label"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Named Workspace Icons"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
StyledText {
width: parent.width
text: "Configure icons for named workspaces. Icons take priority over numbers when both are enabled."
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
wrapMode: Text.WordWrap
}
Repeater {
model: SettingsData.getNamedWorkspaces()
Rectangle {
width: parent.width
height: workspaceIconRow.implicitHeight + Theme.spacingM
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
Theme.surfaceContainer.b, 0.5)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.3)
border.width: 1
Row {
id: workspaceIconRow
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: 150 anchors.leftMargin: Theme.spacingM
elide: Text.ElideRight anchors.rightMargin: Theme.spacingM
} spacing: Theme.spacingM
DankIconPicker { StyledText {
id: iconPicker text: "\"" + modelData + "\""
anchors.verticalCenter: parent.verticalCenter font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
Component.onCompleted: { color: Theme.surfaceText
var iconData = SettingsData.getWorkspaceNameIcon(modelData) anchors.verticalCenter: parent.verticalCenter
if (iconData) { width: 150
setIcon(iconData.value, iconData.type) elide: Text.ElideRight
}
} }
onIconSelected: (iconName, iconType) => { DankIconPicker {
SettingsData.setWorkspaceNameIcon(modelData, { id: iconPicker
type: iconType, anchors.verticalCenter: parent.verticalCenter
value: iconName
})
setIcon(iconName, iconType)
}
Connections { Component.onCompleted: {
target: SettingsData
function onWorkspaceIconsUpdated() {
var iconData = SettingsData.getWorkspaceNameIcon(modelData) var iconData = SettingsData.getWorkspaceNameIcon(modelData)
if (iconData) { if (iconData) {
iconPicker.setIcon(iconData.value, iconData.type) setIcon(iconData.value, iconData.type)
} else { }
iconPicker.setIcon("", "icon") }
onIconSelected: (iconName, iconType) => {
SettingsData.setWorkspaceNameIcon(modelData, {
type: iconType,
value: iconName
})
setIcon(iconName, iconType)
}
Connections {
target: SettingsData
function onWorkspaceIconsUpdated() {
var iconData = SettingsData.getWorkspaceNameIcon(modelData)
if (iconData) {
iconPicker.setIcon(iconData.value, iconData.type)
} else {
iconPicker.setIcon("", "icon")
}
} }
} }
} }
}
Rectangle { Rectangle {
width: 28 width: 28
height: 28 height: 28
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: clearMouseArea.containsMouse ? Theme.errorHover : Theme.surfaceContainer color: clearMouseArea.containsMouse ? Theme.errorHover : Theme.surfaceContainer
border.color: clearMouseArea.containsMouse ? Theme.error : Theme.outline border.color: clearMouseArea.containsMouse ? Theme.error : Theme.outline
border.width: 1 border.width: 1
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
DankIcon { DankIcon {
name: "close" name: "close"
size: 16 size: 16
color: clearMouseArea.containsMouse ? Theme.error : Theme.outline color: clearMouseArea.containsMouse ? Theme.error : Theme.outline
anchors.centerIn: parent anchors.centerIn: parent
} }
MouseArea { MouseArea {
id: clearMouseArea id: clearMouseArea
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
SettingsData.removeWorkspaceNameIcon(modelData) SettingsData.removeWorkspaceNameIcon(modelData)
}
} }
} }
}
Item { Item {
width: parent.width - 150 - 240 - 28 - Theme.spacingM * 4 width: parent.width - 150 - 240 - 28 - Theme.spacingM * 4
height: 1 height: 1
}
} }
} }
} }
@@ -938,6 +888,7 @@ Item {
} }
} }
DankWidgetSelectionPopup { DankWidgetSelectionPopup {
id: widgetSelectionPopup id: widgetSelectionPopup

View File

@@ -85,6 +85,8 @@ Singleton {
handleWorkspacesChanged(event.WorkspacesChanged) handleWorkspacesChanged(event.WorkspacesChanged)
} else if (event.WorkspaceActivated) { } else if (event.WorkspaceActivated) {
handleWorkspaceActivated(event.WorkspaceActivated) handleWorkspaceActivated(event.WorkspaceActivated)
} else if (event.WorkspaceActiveWindowChanged) {
handleWorkspaceActiveWindowChanged(event.WorkspaceActiveWindowChanged)
} else if (event.WindowsChanged) { } else if (event.WindowsChanged) {
handleWindowsChanged(event.WindowsChanged) handleWindowsChanged(event.WindowsChanged)
} else if (event.WindowClosed) { } else if (event.WindowClosed) {
@@ -153,6 +155,49 @@ Singleton {
workspacesChanged() workspacesChanged()
} }
function handleWorkspaceActiveWindowChanged(data) {
// Update the focused window when workspace's active window changes
// This is crucial for handling floating window close scenarios
if (data.active_window_id !== null && data.active_window_id !== undefined) {
focusedWindowId = String(data.active_window_id)
focusedWindowIndex = windows.findIndex(w => w.id == data.active_window_id)
// Create new windows array with updated focus states to trigger property change
let updatedWindows = []
for (let i = 0; i < windows.length; i++) {
let w = windows[i]
let updatedWindow = {}
for (let prop in w) {
updatedWindow[prop] = w[prop]
}
updatedWindow.is_focused = (w.id == data.active_window_id)
updatedWindows.push(updatedWindow)
}
windows = updatedWindows
updateFocusedWindow()
} else {
// No active window in this workspace
focusedWindowId = ""
focusedWindowIndex = -1
// Create new windows array with cleared focus states for this workspace
let updatedWindows = []
for (let i = 0; i < windows.length; i++) {
let w = windows[i]
let updatedWindow = {}
for (let prop in w) {
updatedWindow[prop] = w[prop]
}
updatedWindow.is_focused = w.workspace_id == data.workspace_id ? false : w.is_focused
updatedWindows.push(updatedWindow)
}
windows = updatedWindows
updateFocusedWindow()
}
}
function handleWindowsChanged(data) { function handleWindowsChanged(data) {
windows = [...data.windows].sort((a, b) => a.id - b.id) windows = [...data.windows].sort((a, b) => a.id - b.id)
updateFocusedWindow() updateFocusedWindow()