1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 13:32:50 -05:00

cleanup and qmlfmt some modules

This commit is contained in:
bbedward
2025-09-03 15:00:03 -04:00
parent d4db8a01fe
commit 3856ce14cd
17 changed files with 792 additions and 1393 deletions

View File

@@ -23,10 +23,6 @@ DankPopout {
appLauncher.keyboardNavigationActive = false
}
function hide() {
close()
}
function setTriggerPosition(x, y, width, section, screen) {
triggerX = x
triggerY = y
@@ -46,10 +42,10 @@ DankPopout {
onOpened: {
Qt.callLater(() => {
if (contentLoader.item && contentLoader.item.searchField) {
contentLoader.item.searchField.forceActiveFocus()
}
})
if (contentLoader.item && contentLoader.item.searchField) {
contentLoader.item.searchField.forceActiveFocus()
}
})
}
AppLauncher {
@@ -57,7 +53,7 @@ DankPopout {
viewMode: SettingsData.appLauncherViewMode
gridColumns: 4
onAppLaunched: appDrawerPopout.hide()
onAppLaunched: appDrawerPopout.close()
onViewModeSelected: function (mode) {
SettingsData.setAppLauncherViewMode(mode)
}
@@ -74,34 +70,30 @@ DankPopout {
antialiasing: true
smooth: true
Rectangle {
anchors.fill: parent
anchors.margins: -3
color: "transparent"
radius: parent.radius + 3
border.color: Qt.rgba(0, 0, 0, 0.05)
border.width: 1
z: -3
}
Rectangle {
anchors.fill: parent
anchors.margins: -2
color: "transparent"
radius: parent.radius + 2
border.color: Qt.rgba(0, 0, 0, 0.08)
border.width: 1
z: -2
}
Rectangle {
anchors.fill: parent
color: "transparent"
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.12)
border.width: 1
radius: parent.radius
z: -1
// Multi-layer border effect
Repeater {
model: [{
"margin": -3,
"color": Qt.rgba(0, 0, 0, 0.05),
"z": -3
}, {
"margin": -2,
"color": Qt.rgba(0, 0, 0, 0.08),
"z": -2
}, {
"margin": 0,
"color": Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12),
"z": -1
}]
Rectangle {
anchors.fill: parent
anchors.margins: modelData.margin
color: "transparent"
radius: parent.radius + Math.abs(modelData.margin)
border.color: modelData.color
border.width: 1
z: modelData.z
}
}
Item {
@@ -109,31 +101,30 @@ DankPopout {
anchors.fill: parent
focus: true
readonly property var keyMappings: {
const mappings = {}
mappings[Qt.Key_Escape] = () => appDrawerPopout.close()
mappings[Qt.Key_Down] = () => appLauncher.selectNext()
mappings[Qt.Key_Up] = () => appLauncher.selectPrevious()
mappings[Qt.Key_Return] = () => appLauncher.launchSelected()
mappings[Qt.Key_Enter] = () => appLauncher.launchSelected()
if (appLauncher.viewMode === "grid") {
mappings[Qt.Key_Right] = () => appLauncher.selectNextInRow()
mappings[Qt.Key_Left] = () => appLauncher.selectPreviousInRow()
}
return mappings
}
Keys.onPressed: function (event) {
if (event.key === Qt.Key_Escape) {
appDrawerPopout.close()
if (keyMappings[event.key]) {
keyMappings[event.key]()
event.accepted = true
} else if (event.key === Qt.Key_Down) {
appLauncher.selectNext()
event.accepted = true
} else if (event.key === Qt.Key_Up) {
appLauncher.selectPrevious()
event.accepted = true
} else if (event.key === Qt.Key_Right
&& appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow()
event.accepted = true
} else if (event.key === Qt.Key_Left
&& appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow()
event.accepted = true
} else if (event.key === Qt.Key_Return
|| event.key === Qt.Key_Enter) {
appLauncher.launchSelected()
event.accepted = true
} else if (!searchField.activeFocus && event.text
&& event.text.length > 0 && event.text.match(
/[a-zA-Z0-9\\s]/)) {
return
}
if (!searchField.activeFocus && event.text && /[a-zA-Z0-9\s]/.test(event.text)) {
searchField.forceActiveFocus()
searchField.insertText(event.text)
event.accepted = true
@@ -178,15 +169,8 @@ DankPopout {
width: parent.width
height: 52
cornerRadius: Theme.cornerRadius
backgroundColor: Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
Theme.getContentBackgroundAlpha(
) * 0.7)
normalBorderColor: Qt.rgba(Theme.outline.r,
Theme.outline.g,
Theme.outline.b, 0.3)
backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.7)
normalBorderColor: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
focusedBorderColor: Theme.primary
leftIconName: "search"
leftIconSize: Theme.iconSize
@@ -204,28 +188,34 @@ DankPopout {
if (event.key === Qt.Key_Escape) {
appDrawerPopout.close()
event.accepted = true
} else if ((event.key === Qt.Key_Return
|| event.key === Qt.Key_Enter)
&& text.length > 0) {
if (appLauncher.keyboardNavigationActive
&& appLauncher.model.count > 0) {
return
}
const isEnterKey = [Qt.Key_Return, Qt.Key_Enter].includes(event.key)
const hasText = text.length > 0
if (isEnterKey && hasText) {
if (appLauncher.keyboardNavigationActive && appLauncher.model.count > 0) {
appLauncher.launchSelected()
} else if (appLauncher.model.count > 0) {
var firstApp = appLauncher.model.get(0)
appLauncher.launchApp(firstApp)
appLauncher.launchApp(appLauncher.model.get(0))
}
event.accepted = true
} else if (event.key === Qt.Key_Down || event.key
=== Qt.Key_Up || event.key === Qt.Key_Left || event.key
=== Qt.Key_Right || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
event.accepted = false
return
}
const navigationKeys = [Qt.Key_Down, Qt.Key_Up, Qt.Key_Left, Qt.Key_Right]
const isNavigationKey = navigationKeys.includes(event.key)
const isEmptyEnter = isEnterKey && !hasText
event.accepted = !(isNavigationKey || isEmptyEnter)
}
Connections {
function onShouldBeVisibleChanged() {
if (!appDrawerPopout.shouldBeVisible)
searchField.clearFocus()
if (!appDrawerPopout.shouldBeVisible) {
searchField.focus = false
}
}
target: appDrawerPopout
@@ -268,14 +258,8 @@ DankPopout {
circular: false
iconName: "view_list"
iconSize: 20
iconColor: appLauncher.viewMode
=== "list" ? Theme.primary : Theme.surfaceText
backgroundColor: appLauncher.viewMode
=== "list" ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
iconColor: appLauncher.viewMode === "list" ? Theme.primary : Theme.surfaceText
backgroundColor: appLauncher.viewMode === "list" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
onClicked: {
appLauncher.setViewMode("list")
}
@@ -286,14 +270,8 @@ DankPopout {
circular: false
iconName: "grid_view"
iconSize: 20
iconColor: appLauncher.viewMode
=== "grid" ? Theme.primary : Theme.surfaceText
backgroundColor: appLauncher.viewMode
=== "grid" ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
iconColor: appLauncher.viewMode === "grid" ? Theme.primary : Theme.surfaceText
backgroundColor: appLauncher.viewMode === "grid" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
onClicked: {
appLauncher.setViewMode("grid")
}
@@ -310,11 +288,8 @@ DankPopout {
return parent.height - usedHeight
}
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.1)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.05)
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.1)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
border.width: 1
DankListView {
@@ -408,11 +383,7 @@ DankPopout {
StyledText {
anchors.centerIn: parent
text: (model.name
&& model.name.length
> 0) ? model.name.charAt(
0).toUpperCase(
) : "A"
text: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
font.pixelSize: appList.iconSize * 0.4
color: Theme.primary
font.weight: Font.Bold
@@ -440,9 +411,7 @@ DankPopout {
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
elide: Text.ElideRight
visible: appList.showDescription
&& model.comment
&& model.comment.length > 0
visible: appList.showDescription && model.comment && model.comment.length > 0
}
}
}
@@ -456,8 +425,7 @@ DankPopout {
acceptedButtons: Qt.LeftButton | Qt.RightButton
z: 10
onEntered: {
if (appList.hoverUpdatesSelection
&& !appList.keyboardNavigationActive)
if (appList.hoverUpdatesSelection && !appList.keyboardNavigationActive)
appList.currentIndex = index
}
onPositionChanged: {
@@ -465,16 +433,10 @@ DankPopout {
}
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
appList.itemClicked(
index, model)
appList.itemClicked(index, model)
} else if (mouse.button === Qt.RightButton) {
var panelPos = mapToItem(
contextMenu.parent,
mouse.x, mouse.y)
appList.itemRightClicked(
index, model,
panelPos.x,
panelPos.y)
var panelPos = mapToItem(contextMenu.parent, mouse.x, mouse.y)
appList.itemRightClicked(index, model, panelPos.x, panelPos.y)
}
}
}
@@ -508,8 +470,7 @@ DankPopout {
if (index < 0 || index >= count)
return
var itemY = Math.floor(
index / actualColumns) * cellHeight
var itemY = Math.floor(index / actualColumns) * cellHeight
var itemBottom = itemY + cellHeight
if (itemY < contentY)
contentY = itemY
@@ -524,8 +485,7 @@ DankPopout {
clip: true
cellWidth: baseCellWidth
cellHeight: baseCellHeight
leftMargin: Math.max(Theme.spacingS,
remainingSpace / 2)
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
rightMargin: leftMargin
focus: true
interactive: true
@@ -560,12 +520,7 @@ DankPopout {
spacing: Theme.spacingS
Item {
property int iconSize: Math.min(
appGrid.maxIconSize,
Math.max(
appGrid.minIconSize,
appGrid.cellWidth
* appGrid.iconSizeRatio))
property int iconSize: Math.min(appGrid.maxIconSize, Math.max(appGrid.minIconSize, appGrid.cellWidth * appGrid.iconSizeRatio))
width: iconSize
height: iconSize
@@ -591,14 +546,8 @@ DankPopout {
StyledText {
anchors.centerIn: parent
text: (model.name
&& model.name.length
> 0) ? model.name.charAt(
0).toUpperCase(
) : "A"
font.pixelSize: Math.min(
28,
parent.width * 0.5)
text: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
font.pixelSize: Math.min(28, parent.width * 0.5)
color: Theme.primary
font.weight: Font.Bold
}
@@ -628,8 +577,7 @@ DankPopout {
acceptedButtons: Qt.LeftButton | Qt.RightButton
z: 10
onEntered: {
if (appGrid.hoverUpdatesSelection
&& !appGrid.keyboardNavigationActive)
if (appGrid.hoverUpdatesSelection && !appGrid.keyboardNavigationActive)
appGrid.currentIndex = index
}
onPositionChanged: {
@@ -637,16 +585,10 @@ DankPopout {
}
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
appGrid.itemClicked(
index, model)
appGrid.itemClicked(index, model)
} else if (mouse.button === Qt.RightButton) {
var panelPos = mapToItem(
contextMenu.parent,
mouse.x, mouse.y)
appGrid.itemRightClicked(
index, model,
panelPos.x,
panelPos.y)
var panelPos = mapToItem(contextMenu.parent, mouse.x, mouse.y)
appGrid.itemRightClicked(index, model, panelPos.x, panelPos.y)
}
}
}
@@ -664,6 +606,9 @@ DankPopout {
property var currentApp: null
property bool menuVisible: false
readonly property string appId: (currentApp && currentApp.desktopEntry) ? (currentApp.desktopEntry.id || currentApp.desktopEntry.execString || "") : ""
readonly property bool isPinned: appId && SessionData.isPinnedApp(appId)
function show(x, y, app) {
currentApp = app
@@ -681,12 +626,8 @@ DankPopout {
finalY = y - menuHeight - 8
}
finalX = Math.max(
8, Math.min(finalX,
appDrawerPopout.popupWidth - menuWidth - 8))
finalY = Math.max(8, Math.min(
finalY,
appDrawerPopout.popupHeight - menuHeight - 8))
finalX = Math.max(8, Math.min(finalX, appDrawerPopout.popupWidth - menuWidth - 8))
finalY = Math.max(8, Math.min(finalY, appDrawerPopout.popupHeight - menuHeight - 8))
contextMenu.x = finalX
contextMenu.y = finalY
@@ -706,8 +647,7 @@ DankPopout {
height: menuColumn.implicitHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: Theme.popupBackground()
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.08)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
z: 1000
opacity: menuVisible ? 1 : 0
@@ -735,11 +675,7 @@ DankPopout {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: pinMouseArea.containsMouse ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
color: pinMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left
@@ -748,17 +684,7 @@ DankPopout {
spacing: Theme.spacingS
DankIcon {
name: {
if (!contextMenu.currentApp
|| !contextMenu.currentApp.desktopEntry)
return "push_pin"
var appId = contextMenu.currentApp.desktopEntry.id
|| contextMenu.currentApp.desktopEntry.execString
|| ""
return SessionData.isPinnedApp(
appId) ? "keep_off" : "push_pin"
}
name: contextMenu.isPinned ? "keep_off" : "push_pin"
size: Theme.iconSize - 2
color: Theme.surfaceText
opacity: 0.7
@@ -766,17 +692,7 @@ DankPopout {
}
StyledText {
text: {
if (!contextMenu.currentApp
|| !contextMenu.currentApp.desktopEntry)
return "Pin to Dock"
var appId = contextMenu.currentApp.desktopEntry.id
|| contextMenu.currentApp.desktopEntry.execString
|| ""
return SessionData.isPinnedApp(
appId) ? "Unpin from Dock" : "Pin to Dock"
}
text: contextMenu.isPinned ? "Unpin from Dock" : "Pin to Dock"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
@@ -791,17 +707,15 @@ DankPopout {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (!contextMenu.currentApp
|| !contextMenu.currentApp.desktopEntry)
if (!contextMenu.currentApp || !contextMenu.currentApp.desktopEntry) {
return
}
var appId = contextMenu.currentApp.desktopEntry.id
|| contextMenu.currentApp.desktopEntry.execString
|| ""
if (SessionData.isPinnedApp(appId))
SessionData.removePinnedApp(appId)
else
SessionData.addPinnedApp(appId)
if (contextMenu.isPinned) {
SessionData.removePinnedApp(contextMenu.appId)
} else {
SessionData.addPinnedApp(contextMenu.appId)
}
contextMenu.close()
}
}
@@ -817,8 +731,7 @@ DankPopout {
anchors.centerIn: parent
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
}
}
@@ -826,11 +739,7 @@ DankPopout {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: launchMouseArea.containsMouse ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
color: launchMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
Row {
anchors.left: parent.left

View File

@@ -17,20 +17,12 @@ Item {
property bool debounceSearch: true
property int debounceInterval: 50
property bool keyboardNavigationActive: false
property var categories: {
var allCategories = AppSearchService.getAllCategories().filter(cat => {
return cat !== "Education"
&& cat !== "Science"
})
var result = ["All"]
return result.concat(allCategories.filter(cat => {
return cat !== "All"
}))
readonly property var categories: {
const allCategories = AppSearchService.getAllCategories().filter(cat => cat !== "Education" && cat !== "Science")
const result = ["All"]
return result.concat(allCategories.filter(cat => cat !== "All"))
}
property var categoryIcons: categories.map(category => {
return AppSearchService.getCategoryIcon(
category)
})
readonly property var categoryIcons: categories.map(category => AppSearchService.getCategoryIcon(category))
property var appUsageRanking: AppUsageHistoryData.appUsageRanking || {}
property alias model: filteredModel
property var _watchApplications: AppSearchService.applications
@@ -43,116 +35,96 @@ Item {
filteredModel.clear()
selectedIndex = 0
keyboardNavigationActive = false
var apps = []
let apps = []
if (searchQuery.length === 0) {
if (selectedCategory === "All") {
apps = AppSearchService.getAppsInCategory(
"All") // HACK: Use function call instead of property
} else {
var categoryApps = AppSearchService.getAppsInCategory(
selectedCategory)
apps = categoryApps.slice(0, maxResults)
}
apps = selectedCategory === "All" ? AppSearchService.getAppsInCategory("All") : AppSearchService.getAppsInCategory(selectedCategory).slice(0, maxResults)
} else {
if (selectedCategory === "All") {
apps = AppSearchService.searchApplications(searchQuery)
} else {
var categoryApps = AppSearchService.getAppsInCategory(
selectedCategory)
const categoryApps = AppSearchService.getAppsInCategory(selectedCategory)
if (categoryApps.length > 0) {
var allSearchResults = AppSearchService.searchApplications(
searchQuery)
var categoryNames = new Set(categoryApps.map(app => {
return app.name
}))
apps = allSearchResults.filter(searchApp => {
return categoryNames.has(
searchApp.name)
}).slice(0, maxResults)
const allSearchResults = AppSearchService.searchApplications(searchQuery)
const categoryNames = new Set(categoryApps.map(app => app.name))
apps = allSearchResults.filter(searchApp => categoryNames.has(searchApp.name)).slice(0, maxResults)
} else {
apps = []
}
}
}
if (searchQuery.length === 0)
apps = apps.sort(function (a, b) {
var aId = a.id || (a.execString || a.exec || "")
var bId = b.id || (b.execString || b.exec || "")
var aUsage = appUsageRanking[aId] ? appUsageRanking[aId].usageCount : 0
var bUsage = appUsageRanking[bId] ? appUsageRanking[bId].usageCount : 0
if (aUsage !== bUsage)
return bUsage - aUsage
return (a.name || "").localeCompare(b.name || "")
})
if (searchQuery.length === 0) {
apps = apps.sort((a, b) => {
const aId = a.id || a.execString || a.exec || ""
const bId = b.id || b.execString || b.exec || ""
const aUsage = appUsageRanking[aId] ? appUsageRanking[aId].usageCount : 0
const bUsage = appUsageRanking[bId] ? appUsageRanking[bId].usageCount : 0
if (aUsage !== bUsage) {
return bUsage - aUsage
}
return (a.name || "").localeCompare(b.name || "")
})
}
apps.forEach(app => {
if (app)
filteredModel.append({
"name": app.name || "",
"exec": app.execString || "",
"icon": app.icon
|| "application-x-executable",
"comment": app.comment || "",
"categories": app.categories
|| [],
"desktopEntry": app
})
if (app) {
filteredModel.append({
"name": app.name || "",
"exec": app.execString || "",
"icon": app.icon || "application-x-executable",
"comment": app.comment || "",
"categories": app.categories || [],
"desktopEntry": app
})
}
})
}
function selectNext() {
if (filteredModel.count > 0) {
keyboardNavigationActive = true
if (viewMode === "grid") {
var newIndex = Math.min(selectedIndex + gridColumns,
filteredModel.count - 1)
selectedIndex = newIndex
} else {
selectedIndex = Math.min(selectedIndex + 1,
filteredModel.count - 1)
}
if (filteredModel.count === 0) {
return
}
keyboardNavigationActive = true
selectedIndex = viewMode === "grid" ? Math.min(selectedIndex + gridColumns, filteredModel.count - 1) : Math.min(selectedIndex + 1, filteredModel.count - 1)
}
function selectPrevious() {
if (filteredModel.count > 0) {
keyboardNavigationActive = true
if (viewMode === "grid") {
var newIndex = Math.max(selectedIndex - gridColumns, 0)
selectedIndex = newIndex
} else {
selectedIndex = Math.max(selectedIndex - 1, 0)
}
if (filteredModel.count === 0) {
return
}
keyboardNavigationActive = true
selectedIndex = viewMode === "grid" ? Math.max(selectedIndex - gridColumns, 0) : Math.max(selectedIndex - 1, 0)
}
function selectNextInRow() {
if (filteredModel.count > 0 && viewMode === "grid") {
keyboardNavigationActive = true
selectedIndex = Math.min(selectedIndex + 1, filteredModel.count - 1)
if (filteredModel.count === 0 || viewMode !== "grid") {
return
}
keyboardNavigationActive = true
selectedIndex = Math.min(selectedIndex + 1, filteredModel.count - 1)
}
function selectPreviousInRow() {
if (filteredModel.count > 0 && viewMode === "grid") {
keyboardNavigationActive = true
selectedIndex = Math.max(selectedIndex - 1, 0)
if (filteredModel.count === 0 || viewMode !== "grid") {
return
}
keyboardNavigationActive = true
selectedIndex = Math.max(selectedIndex - 1, 0)
}
function launchSelected() {
if (filteredModel.count > 0 && selectedIndex >= 0
&& selectedIndex < filteredModel.count) {
var selectedApp = filteredModel.get(selectedIndex)
launchApp(selectedApp)
if (filteredModel.count === 0 || selectedIndex < 0 || selectedIndex >= filteredModel.count) {
return
}
const selectedApp = filteredModel.get(selectedIndex)
launchApp(selectedApp)
}
function launchApp(appData) {
if (!appData)
if (!appData) {
return
}
appData.desktopEntry.execute()
appLaunched(appData)
AppUsageHistoryData.addAppUsage(appData.desktopEntry)
@@ -169,10 +141,11 @@ Item {
}
onSearchQueryChanged: {
if (debounceSearch)
if (debounceSearch) {
searchDebounceTimer.restart()
else
} else {
updateFilteredModel()
}
}
onSelectedCategoryChanged: updateFilteredModel()
onAppUsageRankingChanged: updateFilteredModel()

View File

@@ -8,11 +8,25 @@ Item {
property var categories: []
property string selectedCategory: "All"
property bool compact: false // For different layout styles
property bool compact: false
signal categorySelected(string category)
height: compact ? 36 : (72 + Theme.spacingS) // Single row vs two rows
readonly property int maxCompactItems: 8
readonly property int itemHeight: 36
readonly property color selectedBorderColor: "transparent"
readonly property color unselectedBorderColor: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
function handleCategoryClick(category) {
selectedCategory = category
categorySelected(category)
}
function getButtonWidth(itemCount, containerWidth) {
return itemCount > 0 ? (containerWidth - (itemCount - 1) * Theme.spacingS) / itemCount : 0
}
height: compact ? itemHeight : (itemHeight * 2 + Theme.spacingS)
Row {
visible: compact
@@ -20,22 +34,16 @@ Item {
spacing: Theme.spacingS
Repeater {
model: categories.slice(0, Math.min(categories.length,
8)) // Limit for space
model: categories ? categories.slice(0, Math.min(categories.length || 0, maxCompactItems)) : []
Rectangle {
height: 36
width: (parent.width - (Math.min(
categories.length,
8) - 1) * Theme.spacingS) / Math.min(
categories.length, 8)
property int itemCount: Math.min(categories ? categories.length || 0 : 0, maxCompactItems)
height: root.itemHeight
width: root.getButtonWidth(itemCount, parent.width)
radius: Theme.cornerRadius
color: selectedCategory === modelData ? Theme.primary : "transparent"
border.color: selectedCategory === modelData ? "transparent" : Qt.rgba(
Theme.outline.r,
Theme.outline.g,
Theme.outline.b,
0.3)
border.color: selectedCategory === modelData ? selectedBorderColor : unselectedBorderColor
StyledText {
anchors.centerIn: parent
@@ -50,10 +58,7 @@ Item {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
selectedCategory = modelData
categorySelected(modelData)
}
onClicked: root.handleCategoryClick(modelData)
}
}
}
@@ -65,27 +70,20 @@ Item {
spacing: Theme.spacingS
Row {
property var firstRowCategories: categories.slice(
0, Math.min(4,
categories.length))
width: parent.width
spacing: Theme.spacingS
Repeater {
model: parent.firstRowCategories
model: categories ? categories.slice(0, Math.min(4, categories.length || 0)) : []
Rectangle {
height: 36
width: (parent.width - (parent.firstRowCategories.length - 1)
* Theme.spacingS) / parent.firstRowCategories.length
property int itemCount: Math.min(4, categories ? categories.length || 0 : 0)
height: root.itemHeight
width: root.getButtonWidth(itemCount, parent.width)
radius: Theme.cornerRadius
color: selectedCategory === modelData ? Theme.primary : "transparent"
border.color: selectedCategory
=== modelData ? "transparent" : Qt.rgba(
Theme.outline.r,
Theme.outline.g,
Theme.outline.b, 0.3)
border.color: selectedCategory === modelData ? selectedBorderColor : unselectedBorderColor
StyledText {
anchors.centerIn: parent
@@ -100,37 +98,28 @@ Item {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
selectedCategory = modelData
categorySelected(modelData)
}
onClicked: root.handleCategoryClick(modelData)
}
}
}
}
Row {
property var secondRowCategories: categories.slice(
4, categories.length)
width: parent.width
spacing: Theme.spacingS
visible: secondRowCategories.length > 0
visible: categories && categories.length > 4
Repeater {
model: parent.secondRowCategories
model: categories && categories.length > 4 ? categories.slice(4) : []
Rectangle {
height: 36
width: (parent.width - (parent.secondRowCategories.length - 1)
* Theme.spacingS) / parent.secondRowCategories.length
property int itemCount: categories && categories.length > 4 ? categories.length - 4 : 0
height: root.itemHeight
width: root.getButtonWidth(itemCount, parent.width)
radius: Theme.cornerRadius
color: selectedCategory === modelData ? Theme.primary : "transparent"
border.color: selectedCategory
=== modelData ? "transparent" : Qt.rgba(
Theme.outline.r,
Theme.outline.g,
Theme.outline.b, 0.3)
border.color: selectedCategory === modelData ? selectedBorderColor : unselectedBorderColor
StyledText {
anchors.centerIn: parent
@@ -145,10 +134,7 @@ Item {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
selectedCategory = modelData
categorySelected(modelData)
}
onClicked: root.handleCategoryClick(modelData)
}
}
}

View File

@@ -12,35 +12,31 @@ Column {
property date selectedDate: new Date()
function loadEventsForMonth() {
if (!CalendarService || !CalendarService.khalAvailable)
if (!CalendarService || !CalendarService.khalAvailable) {
return
}
const firstDay = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1)
const dayOfWeek = firstDay.getDay()
const startDate = new Date(firstDay)
startDate.setDate(startDate.getDate() - dayOfWeek - 7)
const lastDay = new Date(displayDate.getFullYear(), displayDate.getMonth() + 1, 0)
const endDate = new Date(lastDay)
endDate.setDate(endDate.getDate() + (6 - lastDay.getDay()) + 7)
let firstDay = new Date(displayDate.getFullYear(),
displayDate.getMonth(), 1)
let dayOfWeek = firstDay.getDay()
let startDate = new Date(firstDay)
startDate.setDate(startDate.getDate(
) - dayOfWeek - 7) // Extra week padding
let lastDay = new Date(displayDate.getFullYear(),
displayDate.getMonth() + 1, 0)
let endDate = new Date(lastDay)
endDate.setDate(endDate.getDate() + (6 - lastDay.getDay(
)) + 7) // Extra week padding
CalendarService.loadEvents(startDate, endDate)
}
spacing: Theme.spacingM
onDisplayDateChanged: {
loadEventsForMonth()
}
Component.onCompleted: {
loadEventsForMonth()
}
onDisplayDateChanged: loadEventsForMonth()
Component.onCompleted: loadEventsForMonth()
Connections {
function onKhalAvailableChanged() {
if (CalendarService && CalendarService.khalAvailable)
if (CalendarService && CalendarService.khalAvailable) {
loadEventsForMonth()
}
}
target: CalendarService
@@ -55,10 +51,7 @@ Column {
width: 40
height: 40
radius: Theme.cornerRadius
color: prevMonthArea.containsMouse ? Qt.rgba(Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
color: prevMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
DankIcon {
anchors.centerIn: parent
@@ -96,10 +89,7 @@ Column {
width: 40
height: 40
radius: Theme.cornerRadius
color: nextMonthArea.containsMouse ? Qt.rgba(Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
color: nextMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
DankIcon {
anchors.centerIn: parent
@@ -129,10 +119,10 @@ Column {
Repeater {
model: {
var days = []
var locale = Qt.locale()
const days = []
const locale = Qt.locale()
for (var i = 0; i < 7; i++) {
var date = new Date(2024, 0, 7 + i)
const date = new Date(2024, 0, 7 + i)
days.push(locale.dayName(i, Locale.ShortFormat))
}
return days
@@ -147,8 +137,7 @@ Column {
anchors.centerIn: parent
text: modelData
font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.6)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
font.weight: Font.Medium
}
}
@@ -156,10 +145,9 @@ Column {
}
Grid {
property date firstDay: {
let date = new Date(displayDate.getFullYear(),
displayDate.getMonth(), 1)
let dayOfWeek = date.getDay()
readonly property date firstDay: {
const date = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1)
const dayOfWeek = date.getDay()
date.setDate(date.getDate() - dayOfWeek)
return date
}
@@ -173,17 +161,14 @@ Column {
model: 42
Rectangle {
property date dayDate: {
let date = new Date(parent.firstDay)
readonly property date dayDate: {
const date = new Date(parent.firstDay)
date.setDate(date.getDate() + index)
return date
}
property bool isCurrentMonth: dayDate.getMonth(
) === displayDate.getMonth()
property bool isToday: dayDate.toDateString(
) === new Date().toDateString()
property bool isSelected: dayDate.toDateString(
) === selectedDate.toDateString()
readonly property bool isCurrentMonth: dayDate.getMonth() === displayDate.getMonth()
readonly property bool isToday: dayDate.toDateString() === new Date().toDateString()
readonly property bool isSelected: dayDate.toDateString() === selectedDate.toDateString()
width: parent.width / 7
height: parent.height / 6
@@ -194,11 +179,7 @@ Column {
anchors.centerIn: parent
width: parent.width - 4
height: parent.height - 4
color: isSelected ? Theme.primary : isToday ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : dayArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
color: isSelected ? Theme.primary : isToday ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : dayArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
radius: Theme.cornerRadius
clip: true
@@ -207,8 +188,7 @@ Column {
text: dayDate.getDate()
font.pixelSize: Theme.fontSizeMedium
color: isSelected ? Theme.surface : isToday ? Theme.primary : isCurrentMonth ? Theme.surfaceText : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.4)
font.weight: isToday
|| isSelected ? Font.Medium : Font.Normal
font.weight: isToday || isSelected ? Font.Medium : Font.Normal
}
Rectangle {
@@ -216,17 +196,8 @@ Column {
anchors.fill: parent
radius: parent.radius
visible: CalendarService
&& CalendarService.khalAvailable
&& CalendarService.hasEventsForDate(dayDate)
opacity: {
if (isSelected)
return 0.9
else if (isToday)
return 0.8
else
return 0.6
}
visible: CalendarService && CalendarService.khalAvailable && CalendarService.hasEventsForDate(dayDate)
opacity: isSelected ? 0.9 : isToday ? 0.8 : 0.6
gradient: Gradient {
GradientStop {
@@ -236,26 +207,12 @@ Column {
GradientStop {
position: 0.9
color: {
if (isSelected)
return Qt.lighter(Theme.primary, 1.3)
else if (isToday)
return Theme.primary
else
return Theme.primary
}
color: isSelected ? Qt.lighter(Theme.primary, 1.3) : Theme.primary
}
GradientStop {
position: 1
color: {
if (isSelected)
return Qt.lighter(Theme.primary, 1.3)
else if (isToday)
return Theme.primary
else
return Theme.primary
}
color: isSelected ? Qt.lighter(Theme.primary, 1.3) : Theme.primary
}
}
@@ -274,9 +231,7 @@ Column {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
selectedDate = dayDate
}
onClicked: selectedDate = dayDate
}
}
}

View File

@@ -36,9 +36,7 @@ PanelWindow {
closeTimer.stop()
shouldBeVisible = true
visible = true
Qt.callLater(() => {
calendarGrid.loadEventsForMonth()
})
Qt.callLater(() => calendarGrid.loadEventsForMonth())
} else {
shouldBeVisible = false
closeTimer.restart()
@@ -55,8 +53,9 @@ PanelWindow {
}
}
onVisibleChanged: {
if (visible && calendarGrid)
if (visible && calendarGrid) {
calendarGrid.loadEventsForMonth()
}
}
implicitWidth: 480
implicitHeight: 600
@@ -75,32 +74,27 @@ PanelWindow {
Rectangle {
id: mainContainer
readonly property real targetWidth: Math.min(
(root.screen ? root.screen.width : Screen.width)
* 0.9, 600)
readonly property real targetWidth: Math.min((root.screen ? root.screen.width : Screen.width) * 0.9, 600)
function calculateWidth() {
let baseWidth = 320
if (leftWidgets.hasAnyWidgets)
const baseWidth = 320
if (leftWidgets.hasAnyWidgets) {
return Math.min(parent.width * 0.9, 600)
}
return Math.min(parent.width * 0.7, 400)
}
function calculateHeight() {
let contentHeight = Theme.spacingM * 2
// margins
let widgetHeight = 160
widgetHeight += 140 + Theme.spacingM
let calendarHeight = 300
let mainRowHeight = Math.max(widgetHeight, calendarHeight)
const calendarHeight = 300
const mainRowHeight = Math.max(widgetHeight, calendarHeight)
contentHeight += mainRowHeight + Theme.spacingM
if (CalendarService && CalendarService.khalAvailable) {
let hasEvents = events.selectedDateEvents
&& events.selectedDateEvents.length > 0
let eventsHeight = hasEvents ? Math.min(
300,
80 + events.selectedDateEvents.length * 60) : 120
const hasEvents = events.selectedDateEvents && events.selectedDateEvents.length > 0
const eventsHeight = hasEvents ? Math.min(300, 80 + events.selectedDateEvents.length * 60) : 120
contentHeight += eventsHeight
} else {
contentHeight -= Theme.spacingM
@@ -109,26 +103,22 @@ PanelWindow {
}
readonly property real calculatedX: {
var screenWidth = root.screen ? root.screen.width : Screen.width
const screenWidth = root.screen ? root.screen.width : Screen.width
if (root.triggerSection === "center") {
return (screenWidth - targetWidth) / 2
}
var centerX = root.triggerX + (root.triggerWidth / 2) - (targetWidth / 2)
const centerX = root.triggerX + (root.triggerWidth / 2) - (targetWidth / 2)
if (centerX >= Theme.spacingM
&& centerX + targetWidth <= screenWidth - Theme.spacingM) {
if (centerX >= Theme.spacingM && centerX + targetWidth <= screenWidth - Theme.spacingM) {
return centerX
}
if (centerX < Theme.spacingM) {
return Theme.spacingM
}
if (centerX + targetWidth > screenWidth - Theme.spacingM) {
return screenWidth - targetWidth - Theme.spacingM
}
return centerX
}
@@ -136,8 +126,7 @@ PanelWindow {
height: calculateHeight()
color: Theme.surfaceContainer
radius: Theme.cornerRadius
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.08)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
layer.enabled: true
opacity: shouldBeVisible ? 1 : 0
@@ -145,21 +134,24 @@ PanelWindow {
x: calculatedX
y: root.triggerY
onOpacityChanged: {
if (opacity === 1)
if (opacity === 1) {
Qt.callLater(() => {
height = calculateHeight()
})
}
}
Connections {
function onEventsByDateChanged() {
if (mainContainer.opacity === 1)
if (mainContainer.opacity === 1) {
mainContainer.height = mainContainer.calculateHeight()
}
}
function onKhalAvailableChanged() {
if (mainContainer.opacity === 1)
if (mainContainer.opacity === 1) {
mainContainer.height = mainContainer.calculateHeight()
}
}
target: CalendarService
@@ -168,8 +160,9 @@ PanelWindow {
Connections {
function onSelectedDateEventsChanged() {
if (mainContainer.opacity === 1)
if (mainContainer.opacity === 1) {
mainContainer.height = mainContainer.calculateHeight()
}
}
target: events
@@ -178,8 +171,7 @@ PanelWindow {
Rectangle {
anchors.fill: parent
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g,
Theme.surfaceTint.b, 0.04)
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
radius: parent.radius
SequentialAnimation on opacity {
@@ -219,10 +211,8 @@ PanelWindow {
width: parent.width
height: {
let widgetHeight = 160
// Media widget
widgetHeight += 140 + Theme.spacingM // Weather/SystemInfo widget with spacing
let calendarHeight = 300
// Calendar
widgetHeight += 140 + Theme.spacingM
const calendarHeight = 300
return Math.max(widgetHeight, calendarHeight)
}
spacing: Theme.spacingM
@@ -232,8 +222,7 @@ PanelWindow {
property bool hasAnyWidgets: true
width: hasAnyWidgets ? parent.width
* 0.42 : 0 // Slightly narrower for better proportions
width: hasAnyWidgets ? parent.width * 0.42 : 0
height: childrenRect.height
spacing: Theme.spacingM
visible: hasAnyWidgets
@@ -258,15 +247,11 @@ PanelWindow {
}
Rectangle {
width: leftWidgets.hasAnyWidgets ? parent.width - leftWidgets.width
- Theme.spacingM : parent.width
width: leftWidgets.hasAnyWidgets ? parent.width - leftWidgets.width - Theme.spacingM : parent.width
height: parent.height
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.08)
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.08)
border.width: 1
CalendarGrid {
@@ -317,10 +302,10 @@ PanelWindow {
z: -1
enabled: shouldBeVisible
onClicked: function (mouse) {
var localPos = mapToItem(mainContainer, mouse.x, mouse.y)
if (localPos.x < 0 || localPos.x > mainContainer.width
|| localPos.y < 0 || localPos.y > mainContainer.height)
const localPos = mapToItem(mainContainer, mouse.x, mouse.y)
if (localPos.x < 0 || localPos.x > mainContainer.width || localPos.y < 0 || localPos.y > mainContainer.height) {
calendarVisible = false
}
}
}
}

View File

@@ -14,7 +14,7 @@ Rectangle {
function updateSelectedDateEvents() {
if (CalendarService && CalendarService.khalAvailable) {
let events = CalendarService.getEventsForDate(selectedDate)
const events = CalendarService.getEventsForDate(selectedDate)
selectedDateEvents = events
} else {
selectedDateEvents = []
@@ -25,23 +25,15 @@ Rectangle {
eventsList.model = selectedDateEvents
}
width: parent.width
height: shouldShow ? (hasEvents ? Math.min(
300,
80 + selectedDateEvents.length * 60) : 120) : 0
height: shouldShow ? (hasEvents ? Math.min(300, 80 + selectedDateEvents.length * 60) : 120) : 0
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.12)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.08)
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
visible: shouldShow
layer.enabled: true
Component.onCompleted: {
updateSelectedDateEvents()
}
onSelectedDateChanged: {
updateSelectedDateEvents()
}
Component.onCompleted: updateSelectedDateEvents()
onSelectedDateChanged: updateSelectedDateEvents()
Connections {
function onEventsByDateChanged() {
@@ -73,11 +65,7 @@ Rectangle {
}
StyledText {
text: hasEvents ? (Qt.formatDate(selectedDate, "MMM d") + " • "
+ (selectedDateEvents.length
=== 1 ? "1 event" : selectedDateEvents.length
+ " events")) : Qt.formatDate(
selectedDate, "MMM d")
text: hasEvents ? (Qt.formatDate(selectedDate, "MMM d") + " • " + (selectedDateEvents.length === 1 ? "1 event" : selectedDateEvents.length + " events")) : Qt.formatDate(selectedDate, "MMM d")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
@@ -93,16 +81,14 @@ Rectangle {
DankIcon {
name: "event_busy"
size: Theme.iconSize + 8
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.3)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: "No events"
font.pixelSize: Theme.fontSizeMedium
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.5)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
font.weight: Font.Normal
anchors.horizontalCenter: parent.horizontalCenter
}
@@ -123,7 +109,6 @@ Rectangle {
spacing: Theme.spacingS
boundsBehavior: Flickable.StopAtBounds
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
interactive: true
flickDeceleration: 1500
maximumFlickVelocity: 2000
@@ -131,26 +116,20 @@ Rectangle {
pressDelay: 0
flickableDirection: Flickable.VerticalFlick
// Custom wheel handler for Qt 6.9+ responsive mouse wheel scrolling
WheelHandler {
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
property real momentum: 0
onWheel: event => {
if (event.pixelDelta.y !== 0) {
// Touchpad with pixel delta
momentum = event.pixelDelta.y * 1.8
} else {
// Mouse wheel with angle delta
momentum = (event.angleDelta.y / 120)
* (60 * 2.5) // ~2.5 items per wheel step
momentum = (event.angleDelta.y / 120) * (60 * 2.5)
}
let newY = parent.contentY - momentum
newY = Math.max(
0, Math.min(parent.contentHeight - parent.height,
newY))
newY = Math.max(0, Math.min(parent.contentHeight - parent.height, newY))
parent.contentY = newY
momentum *= 0.92 // Decay for smooth momentum
momentum *= 0.92
event.accepted = true
}
}
@@ -167,22 +146,19 @@ Rectangle {
height: eventContent.implicitHeight + Theme.spacingM
radius: Theme.cornerRadius
color: {
if (modelData.url && eventMouseArea.containsMouse)
return Qt.rgba(Theme.primary.r, Theme.primary.g,
Theme.primary.b, 0.12)
else if (eventMouseArea.containsMouse)
return Qt.rgba(Theme.primary.r, Theme.primary.g,
Theme.primary.b, 0.06)
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.06)
if (modelData.url && eventMouseArea.containsMouse) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
} else if (eventMouseArea.containsMouse) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06)
}
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.06)
}
border.color: {
if (modelData.url && eventMouseArea.containsMouse)
return Qt.rgba(Theme.primary.r, Theme.primary.g,
Theme.primary.b, 0.3)
else if (eventMouseArea.containsMouse)
return Qt.rgba(Theme.primary.r, Theme.primary.g,
Theme.primary.b, 0.15)
if (modelData.url && eventMouseArea.containsMouse) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3)
} else if (eventMouseArea.containsMouse) {
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.15)
}
return "transparent"
}
border.width: 1
@@ -233,9 +209,7 @@ Rectangle {
DankIcon {
name: "schedule"
size: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
anchors.verticalCenter: parent.verticalCenter
}
@@ -244,23 +218,16 @@ Rectangle {
if (modelData.allDay) {
return "All day"
} else {
let timeFormat = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"
let startTime = Qt.formatTime(
modelData.start, timeFormat)
if (modelData.start.toDateString(
) !== modelData.end.toDateString(
) || modelData.start.getTime(
) !== modelData.end.getTime())
return startTime + " " + Qt.formatTime(
modelData.end, timeFormat)
const timeFormat = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"
const startTime = Qt.formatTime(modelData.start, timeFormat)
if (modelData.start.toDateString() !== modelData.end.toDateString() || modelData.start.getTime() !== modelData.end.getTime()) {
return startTime + " " + Qt.formatTime(modelData.end, timeFormat)
}
return startTime
}
}
font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
font.weight: Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
@@ -277,18 +244,14 @@ Rectangle {
DankIcon {
name: "location_on"
size: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: modelData.location
font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
maximumLineCount: 1
@@ -307,8 +270,9 @@ Rectangle {
enabled: modelData.url !== ""
onClicked: {
if (modelData.url && modelData.url !== "") {
if (Qt.openUrlExternally(modelData.url) === false)
if (Qt.openUrlExternally(modelData.url) === false) {
console.warn("Failed to open URL: " + modelData.url)
}
}
}
}

View File

@@ -15,30 +15,27 @@ Rectangle {
property string lastValidArtist: ""
property string lastValidAlbum: ""
property string lastValidArtUrl: ""
property real currentPosition: activePlayer
&& activePlayer.positionSupported ? activePlayer.position : 0
property real currentPosition: activePlayer && activePlayer.positionSupported ? activePlayer.position : 0
property real displayPosition: currentPosition
function ratio() {
readonly property real ratio: {
if (!activePlayer || activePlayer.length <= 0) {
return 0
}
let calculatedRatio = displayPosition / activePlayer.length
const calculatedRatio = displayPosition / activePlayer.length
return Math.max(0, Math.min(1, calculatedRatio))
}
onActivePlayerChanged: {
if (activePlayer && activePlayer.positionSupported) {
currentPosition = Qt.binding(() => activePlayer.position)
currentPosition = Qt.binding(() => activePlayer?.position)
}
}
Timer {
id: positionTimer
interval: 300
running: activePlayer
&& activePlayer.playbackState === MprisPlaybackState.Playing
&& !progressMouseArea.isSeeking
running: activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing && !progressMouseArea.isSeeking
repeat: true
onTriggered: activePlayer && activePlayer.positionSupported && activePlayer.positionChanged()
}
@@ -46,14 +43,11 @@ Rectangle {
width: parent.width
height: parent.height
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
Theme.surfaceContainer.b, 0.4)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.08)
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.4)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
layer.enabled: true
Timer {
id: cleanupTimer
@@ -69,7 +63,6 @@ Rectangle {
}
}
Item {
anchors.fill: parent
anchors.margins: Theme.spacingS
@@ -77,23 +70,19 @@ Rectangle {
Column {
anchors.centerIn: parent
spacing: Theme.spacingS
visible: (!activePlayer && !lastValidTitle)
|| (activePlayer && activePlayer.trackTitle === ""
&& lastValidTitle === "")
visible: (!activePlayer && !lastValidTitle) || (activePlayer && activePlayer.trackTitle === "" && lastValidTitle === "")
DankIcon {
name: "music_note"
size: Theme.iconSize + 8
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.5)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: "No Media Playing"
font.pixelSize: Theme.fontSizeMedium
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
anchors.horizontalCenter: parent.horizontalCenter
}
}
@@ -101,8 +90,7 @@ Rectangle {
Column {
anchors.fill: parent
spacing: Theme.spacingS
visible: activePlayer && activePlayer.trackTitle !== ""
|| lastValidTitle !== ""
visible: (activePlayer && activePlayer.trackTitle !== "") || lastValidTitle !== ""
Row {
width: parent.width
@@ -113,9 +101,7 @@ Rectangle {
width: 60
height: 60
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
Item {
anchors.fill: parent
@@ -125,12 +111,11 @@ Rectangle {
id: albumArt
anchors.fill: parent
source: activePlayer && activePlayer.trackArtUrl
|| lastValidArtUrl || ""
source: (activePlayer && activePlayer.trackArtUrl) || lastValidArtUrl || ""
onSourceChanged: {
if (activePlayer && activePlayer.trackArtUrl
&& albumArt.status !== Image.Error)
if (activePlayer && activePlayer.trackArtUrl && albumArt.status !== Image.Error) {
lastValidArtUrl = activePlayer.trackArtUrl
}
}
fillMode: Image.PreserveAspectCrop
smooth: true
@@ -168,11 +153,11 @@ Rectangle {
spacing: Theme.spacingXS
StyledText {
text: activePlayer && activePlayer.trackTitle
|| lastValidTitle || "Unknown Track"
text: (activePlayer && activePlayer.trackTitle) || lastValidTitle || "Unknown Track"
onTextChanged: {
if (activePlayer && activePlayer.trackTitle)
if (activePlayer && activePlayer.trackTitle) {
lastValidTitle = activePlayer.trackTitle
}
}
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Bold
@@ -184,16 +169,14 @@ Rectangle {
}
StyledText {
text: activePlayer && activePlayer.trackArtist
|| lastValidArtist || "Unknown Artist"
text: (activePlayer && activePlayer.trackArtist) || lastValidArtist || "Unknown Artist"
onTextChanged: {
if (activePlayer && activePlayer.trackArtist)
if (activePlayer && activePlayer.trackArtist) {
lastValidArtist = activePlayer.trackArtist
}
}
font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b, 0.8)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8)
width: parent.width
elide: Text.ElideRight
wrapMode: Text.NoWrap
@@ -201,16 +184,14 @@ Rectangle {
}
StyledText {
text: activePlayer && activePlayer.trackAlbum
|| lastValidAlbum || ""
text: (activePlayer && activePlayer.trackAlbum) || lastValidAlbum || ""
onTextChanged: {
if (activePlayer && activePlayer.trackAlbum)
if (activePlayer && activePlayer.trackAlbum) {
lastValidAlbum = activePlayer.trackAlbum
}
}
font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b, 0.6)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
width: parent.width
elide: Text.ElideRight
wrapMode: Text.NoWrap
@@ -232,9 +213,7 @@ Rectangle {
width: parent.width
height: 6
radius: 3
color: Qt.rgba(Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.3)
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
visible: activePlayer !== null
anchors.verticalCenter: parent.verticalCenter
@@ -244,8 +223,7 @@ Rectangle {
height: parent.height
radius: parent.radius
color: Theme.primary
width: Math.max(0, Math.min(parent.width,
parent.width * ratio()))
width: Math.max(0, Math.min(parent.width, parent.width * ratio))
Behavior on width {
NumberAnimation {
@@ -263,12 +241,10 @@ Rectangle {
color: Theme.primary
border.color: Qt.lighter(Theme.primary, 1.3)
border.width: 1
x: Math.max(0, Math.min(parent.width - width,
progressFill.width - width / 2))
x: Math.max(0, Math.min(parent.width - width, progressFill.width - width / 2))
anchors.verticalCenter: parent.verticalCenter
visible: activePlayer && activePlayer.length > 0
scale: progressMouseArea.containsMouse
|| progressMouseArea.pressed ? 1.2 : 1
scale: progressMouseArea.containsMouse || progressMouseArea.pressed ? 1.2 : 1
Behavior on scale {
NumberAnimation {
@@ -290,66 +266,51 @@ Rectangle {
repeat: false
onTriggered: {
if (progressMouseArea.pendingSeekPosition >= 0 && activePlayer && activePlayer.canSeek && activePlayer.length > 0) {
let clampedPosition = Math.min(progressMouseArea.pendingSeekPosition, activePlayer.length * 0.99)
const clampedPosition = Math.min(progressMouseArea.pendingSeekPosition, activePlayer.length * 0.99)
activePlayer.position = clampedPosition
progressMouseArea.pendingSeekPosition = -1
}
}
}
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
enabled: activePlayer && activePlayer.length > 0
&& activePlayer.canSeek
enabled: activePlayer && activePlayer.length > 0 && activePlayer.canSeek
preventStealing: true
onPressed: function (mouse) {
isSeeking = true
if (activePlayer && activePlayer.length > 0
&& activePlayer.canSeek) {
let ratio = Math.max(
0, Math.min(
1,
mouse.x / progressBarBackground.width))
pendingSeekPosition = ratio * activePlayer.length
displayPosition = pendingSeekPosition
seekDebounceTimer.restart()
}
}
onPressed: mouse => {
isSeeking = true
if (activePlayer && activePlayer.length > 0 && activePlayer.canSeek) {
const ratio = Math.max(0, Math.min(1, mouse.x / progressBarBackground.width))
pendingSeekPosition = ratio * activePlayer.length
displayPosition = pendingSeekPosition
seekDebounceTimer.restart()
}
}
onReleased: {
isSeeking = false
seekDebounceTimer.stop()
if (pendingSeekPosition >= 0 && activePlayer && activePlayer.canSeek && activePlayer.length > 0) {
let clampedPosition = Math.min(pendingSeekPosition, activePlayer.length * 0.99)
const clampedPosition = Math.min(pendingSeekPosition, activePlayer.length * 0.99)
activePlayer.position = clampedPosition
pendingSeekPosition = -1
}
displayPosition = Qt.binding(() => currentPosition)
}
onPositionChanged: function (mouse) {
if (pressed && isSeeking && activePlayer
&& activePlayer.length > 0
&& activePlayer.canSeek) {
let ratio = Math.max(
0, Math.min(
1,
mouse.x / progressBarBackground.width))
pendingSeekPosition = ratio * activePlayer.length
displayPosition = pendingSeekPosition
seekDebounceTimer.restart()
}
}
onClicked: function (mouse) {
if (activePlayer && activePlayer.length > 0
&& activePlayer.canSeek) {
let ratio = Math.max(
0, Math.min(
1,
mouse.x / progressBarBackground.width))
activePlayer.position = ratio * activePlayer.length
}
}
onPositionChanged: mouse => {
if (pressed && isSeeking && activePlayer && activePlayer.length > 0 && activePlayer.canSeek) {
const ratio = Math.max(0, Math.min(1, mouse.x / progressBarBackground.width))
pendingSeekPosition = ratio * activePlayer.length
displayPosition = pendingSeekPosition
seekDebounceTimer.restart()
}
}
onClicked: mouse => {
if (activePlayer && activePlayer.length > 0 && activePlayer.canSeek) {
const ratio = Math.max(0, Math.min(1, mouse.x / progressBarBackground.width))
activePlayer.position = ratio * activePlayer.length
}
}
}
MouseArea {
@@ -362,26 +323,20 @@ Rectangle {
enabled: progressMouseArea.isSeeking
visible: false
preventStealing: true
onPositionChanged: function (mouse) {
if (progressMouseArea.isSeeking && activePlayer
&& activePlayer.length > 0
&& activePlayer.canSeek) {
let globalPos = mapToItem(progressBarBackground,
mouse.x, mouse.y)
let ratio = Math.max(
0, Math.min(
1,
globalPos.x / progressBarBackground.width))
progressMouseArea.pendingSeekPosition = ratio * activePlayer.length
displayPosition = progressMouseArea.pendingSeekPosition
seekDebounceTimer.restart()
}
}
onPositionChanged: mouse => {
if (progressMouseArea.isSeeking && activePlayer && activePlayer.length > 0 && activePlayer.canSeek) {
const globalPos = mapToItem(progressBarBackground, mouse.x, mouse.y)
const ratio = Math.max(0, Math.min(1, globalPos.x / progressBarBackground.width))
progressMouseArea.pendingSeekPosition = ratio * activePlayer.length
displayPosition = progressMouseArea.pendingSeekPosition
seekDebounceTimer.restart()
}
}
onReleased: {
progressMouseArea.isSeeking = false
seekDebounceTimer.stop()
if (progressMouseArea.pendingSeekPosition >= 0 && activePlayer && activePlayer.canSeek && activePlayer.length > 0) {
let clampedPosition = Math.min(progressMouseArea.pendingSeekPosition, activePlayer.length * 0.99)
const clampedPosition = Math.min(progressMouseArea.pendingSeekPosition, activePlayer.length * 0.99)
activePlayer.position = clampedPosition
progressMouseArea.pendingSeekPosition = -1
}
@@ -404,11 +359,7 @@ Rectangle {
width: 28
height: 28
radius: 14
color: prevBtnArea.containsMouse ? Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
0.12) : "transparent"
color: prevBtnArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12) : "transparent"
DankIcon {
anchors.centerIn: parent
@@ -424,11 +375,11 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (!activePlayer)
if (!activePlayer) {
return
}
if (activePlayer.position > 8
&& activePlayer.canSeek) {
if (activePlayer.position > 8 && activePlayer.canSeek) {
activePlayer.position = 0
} else {
activePlayer.previous()
@@ -445,8 +396,7 @@ Rectangle {
DankIcon {
anchors.centerIn: parent
name: activePlayer && activePlayer.playbackState
=== MprisPlaybackState.Playing ? "pause" : "play_arrow"
name: activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow"
size: 20
color: Theme.background
}
@@ -455,8 +405,7 @@ Rectangle {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: activePlayer
&& activePlayer.togglePlaying()
onClicked: activePlayer && activePlayer.togglePlaying()
}
}
@@ -464,11 +413,7 @@ Rectangle {
width: 28
height: 28
radius: 14
color: nextBtnArea.containsMouse ? Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
0.12) : "transparent"
color: nextBtnArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12) : "transparent"
DankIcon {
anchors.centerIn: parent

View File

@@ -7,14 +7,15 @@ Rectangle {
id: root
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
Theme.surfaceContainer.b, 0.4)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.08)
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.4)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
Ref {
service: DgopService
Component.onCompleted: {
DgopService.addRef(["system", "hardware"])
}
Component.onDestruction: {
DgopService.removeRef(["system", "hardware"])
}
Column {
@@ -48,8 +49,7 @@ Rectangle {
StyledText {
text: DgopService.distribution + " • " + DgopService.architecture
font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
width: parent.width
elide: Text.ElideRight
}
@@ -59,8 +59,7 @@ Rectangle {
Rectangle {
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.1)
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
}
Column {
@@ -86,8 +85,7 @@ Rectangle {
StyledText {
text: DgopService.processCount + " proc, " + DgopService.threadCount + " threads"
font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.8)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.8)
width: parent.width
elide: Text.ElideRight
}
@@ -95,43 +93,36 @@ Rectangle {
}
function formatUptime(uptime) {
if (!uptime)
if (!uptime) {
return "0m"
}
// Parse the uptime string - handle formats like "1 week, 4 days, 3:45" or "4 days, 3:45" or "3:45"
var uptimeStr = uptime.toString().trim()
// Check for weeks and days - need to add them together
var weekMatch = uptimeStr.match(/(\d+)\s+weeks?/)
var dayMatch = uptimeStr.match(/(\d+)\s+days?/)
const uptimeStr = uptime.toString().trim()
const weekMatch = uptimeStr.match(/(\d+)\s+weeks?/)
const dayMatch = uptimeStr.match(/(\d+)\s+days?/)
if (weekMatch) {
var weeks = parseInt(weekMatch[1])
var totalDays = weeks * 7
const weeks = parseInt(weekMatch[1])
let totalDays = weeks * 7
if (dayMatch) {
var days = parseInt(dayMatch[1])
const days = parseInt(dayMatch[1])
totalDays += days
}
return totalDays + "d"
} else if (dayMatch) {
var days = parseInt(dayMatch[1])
}
if (dayMatch) {
const days = parseInt(dayMatch[1])
return days + "d"
}
// If it's just hours:minutes, show the largest unit
var timeMatch = uptimeStr.match(/(\d+):(\d+)/)
const timeMatch = uptimeStr.match(/(\d+):(\d+)/)
if (timeMatch) {
var hours = parseInt(timeMatch[1])
var minutes = parseInt(timeMatch[2])
if (hours > 0) {
return hours + "h"
} else {
return minutes + "m"
}
const hours = parseInt(timeMatch[1])
const minutes = parseInt(timeMatch[2])
return hours > 0 ? hours + "h" : minutes + "m"
}
// Fallback - return as is but truncated
return uptimeStr.length > 8 ? uptimeStr.substring(0,
8) + "…" : uptimeStr
return uptimeStr.length > 8 ? uptimeStr.substring(0, 8) + "…" : uptimeStr
}
}

View File

@@ -11,10 +11,8 @@ Rectangle {
width: parent.width
height: parent.height
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g,
Theme.surfaceContainer.b, 0.4)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.08)
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.4)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
layer.enabled: true
@@ -25,22 +23,19 @@ Rectangle {
Column {
anchors.centerIn: parent
spacing: Theme.spacingS
visible: !WeatherService.weather.available
|| WeatherService.weather.temp === 0
visible: !WeatherService.weather.available || WeatherService.weather.temp === 0
DankIcon {
name: "cloud_off"
size: Theme.iconSize + 8
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.5)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
anchors.horizontalCenter: parent.horizontalCenter
}
StyledText {
text: "No Weather Data"
font.pixelSize: Theme.fontSizeMedium
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
anchors.horizontalCenter: parent.horizontalCenter
}
}
@@ -49,8 +44,7 @@ Rectangle {
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingS
visible: WeatherService.weather.available
&& WeatherService.weather.temp !== 0
visible: WeatherService.weather.available && WeatherService.weather.temp !== 0
Item {
width: parent.width
@@ -60,8 +54,7 @@ Rectangle {
id: refreshButton
name: "refresh"
size: Theme.iconSize - 6
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.3)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
anchors.right: parent.right
anchors.top: parent.top
anchors.rightMargin: -Theme.spacingS
@@ -102,8 +95,7 @@ Rectangle {
spacing: Theme.spacingL
DankIcon {
name: WeatherService.getWeatherIcon(
WeatherService.weather.wCode)
name: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
size: Theme.iconSize + 8
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
@@ -114,8 +106,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: (SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp)
+ "°" + (SettingsData.useFahrenheit ? "F" : "C")
text: (SettingsData.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" + (SettingsData.useFahrenheit ? "F" : "C")
font.pixelSize: Theme.fontSizeXLarge
color: Theme.surfaceText
font.weight: Font.Light
@@ -125,9 +116,9 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (WeatherService.weather.available)
SettingsData.setTemperatureUnit(
!SettingsData.useFahrenheit)
if (WeatherService.weather.available) {
SettingsData.setTemperatureUnit(!SettingsData.useFahrenheit)
}
}
enabled: WeatherService.weather.available
}
@@ -136,9 +127,7 @@ Rectangle {
StyledText {
text: WeatherService.weather.city || ""
font.pixelSize: Theme.fontSizeMedium
color: Qt.rgba(Theme.surfaceText.r,
Theme.surfaceText.g,
Theme.surfaceText.b, 0.7)
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
visible: text.length > 0
}
}
@@ -161,8 +150,7 @@ Rectangle {
}
StyledText {
text: WeatherService.weather.humidity ? WeatherService.weather.humidity
+ "%" : "--"
text: WeatherService.weather.humidity ? WeatherService.weather.humidity + "%" : "--"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter

View File

@@ -19,20 +19,16 @@ PanelWindow {
property bool autoHide: SettingsData.dockAutoHide
property real backgroundTransparency: SettingsData.dockTransparency
property bool contextMenuOpen: (contextMenu && contextMenu.visible
&& contextMenu.screen === modelData)
property bool contextMenuOpen: (contextMenu && contextMenu.visible && contextMenu.screen === modelData)
property bool windowIsFullscreen: {
if (!ToplevelManager.activeToplevel)
if (!ToplevelManager.activeToplevel) {
return false
var activeWindow = ToplevelManager.activeToplevel
var fullscreenApps = ["vlc", "mpv", "kodi", "steam", "lutris", "wine", "dosbox"]
return fullscreenApps.some(app => activeWindow.appId
&& activeWindow.appId.toLowerCase(
).includes(app))
}
const activeWindow = ToplevelManager.activeToplevel
const fullscreenApps = ["vlc", "mpv", "kodi", "steam", "lutris", "wine", "dosbox"]
return fullscreenApps.some(app => activeWindow.appId && activeWindow.appId.toLowerCase().includes(app))
}
property bool reveal: (!autoHide || dockMouseArea.containsMouse
|| dockApps.requestDockShow || contextMenuOpen)
&& !windowIsFullscreen
property bool reveal: (!autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen) && !windowIsFullscreen
Connections {
target: SettingsData
@@ -68,7 +64,7 @@ PanelWindow {
property real currentScreen: modelData ? modelData : dock.screen
property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920
property real maxDockWidth: Math.min(screenWidth * 0.8, 1200)
height: dock.reveal ? 65 : 20
width: dock.reveal ? Math.min(dockBackground.width + 32, maxDockWidth) : Math.min(Math.max(dockBackground.width + 64, 200), screenWidth * 0.5)
anchors {
@@ -115,9 +111,7 @@ PanelWindow {
anchors.topMargin: 4
anchors.bottomMargin: 1
color: Qt.rgba(Theme.surfaceContainer.r,
Theme.surfaceContainer.g,
Theme.surfaceContainer.b, backgroundTransparency)
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency)
radius: Theme.cornerRadius
border.width: 1
border.color: Theme.outlineMedium
@@ -125,8 +119,7 @@ PanelWindow {
Rectangle {
anchors.fill: parent
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g,
Theme.surfaceTint.b, 0.04)
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
radius: parent.radius
}
@@ -147,24 +140,24 @@ PanelWindow {
id: appTooltip
property var hoveredButton: {
if (!dockApps.children[0])
if (!dockApps.children[0]) {
return null
var row = dockApps.children[0]
var repeater = null
}
const row = dockApps.children[0]
let repeater = null
for (var i = 0; i < row.children.length; i++) {
var child = row.children[i]
if (child && typeof child.count !== "undefined"
&& typeof child.itemAt === "function") {
const child = row.children[i]
if (child && typeof child.count !== "undefined" && typeof child.itemAt === "function") {
repeater = child
break
}
}
if (!repeater || !repeater.itemAt)
if (!repeater || !repeater.itemAt) {
return null
}
for (var i = 0; i < repeater.count; i++) {
var item = repeater.itemAt(i)
if (item && item.dockButton
&& item.dockButton.showTooltip) {
const item = repeater.itemAt(i)
if (item && item.dockButton && item.dockButton.showTooltip) {
return item.dockButton
}
}
@@ -183,9 +176,7 @@ PanelWindow {
border.color: Theme.outlineMedium
y: -height - 8
x: hoveredButton ? hoveredButton.mapToItem(
dockContainer, hoveredButton.width / 2,
0).x - width / 2 : 0
x: hoveredButton ? hoveredButton.mapToItem(dockContainer, hoveredButton.width / 2, 0).x - width / 2 : 0
StyledText {
id: tooltipLabel

View File

@@ -28,49 +28,48 @@ Item {
if (!appData || appData.type !== "window") {
return false
}
var toplevel = getToplevelObject()
const toplevel = getToplevelObject()
if (!toplevel) {
return false
}
return toplevel.activated
}
property string tooltipText: {
if (!appData)
if (!appData) {
return ""
}
// For window type, show app name + window title
if (appData.type === "window" && showWindowTitle) {
var desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
var appName = desktopEntry
&& desktopEntry.name ? desktopEntry.name : appData.appId
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
const appName = desktopEntry && desktopEntry.name ? desktopEntry.name : appData.appId
return appName + (windowTitle ? " • " + windowTitle : "")
}
// For pinned apps, just show app name
if (!appData.appId)
return ""
var desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
return desktopEntry
&& desktopEntry.name ? desktopEntry.name : appData.appId
if (!appData.appId) {
return ""
}
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
return desktopEntry && desktopEntry.name ? desktopEntry.name : appData.appId
}
width: 40
height: 40
function getToplevelObject() {
if (!appData || appData.type !== "window") {
return null
}
var sortedToplevels = CompositorService.sortedToplevels
const sortedToplevels = CompositorService.sortedToplevels
if (!sortedToplevels) {
return null
}
if (appData.uniqueId) {
for (var i = 0; i < sortedToplevels.length; i++) {
var toplevel = sortedToplevels[i]
var checkId = toplevel.title + "|" + (toplevel.appId || "") + "|" + i
const toplevel = sortedToplevels[i]
const checkId = toplevel.title + "|" + (toplevel.appId || "") + "|" + i
if (checkId === appData.uniqueId) {
return toplevel
}
@@ -82,7 +81,7 @@ Item {
return sortedToplevels[appData.windowId]
}
}
return null
}
onIsHoveredChanged: {
@@ -148,8 +147,9 @@ Item {
interval: 500
repeat: false
onTriggered: {
if (appData && appData.isPinned)
if (appData && appData.isPinned) {
longPressing = true
}
}
}
@@ -162,8 +162,7 @@ Item {
cursorShape: longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
onPressed: mouse => {
if (mouse.button === Qt.LeftButton && appData
&& appData.isPinned) {
if (mouse.button === Qt.LeftButton && appData && appData.isPinned) {
dragStartPos = Qt.point(mouse.x, mouse.y)
longPressTimer.start()
}
@@ -171,9 +170,9 @@ Item {
onReleased: mouse => {
longPressTimer.stop()
if (longPressing) {
if (dragging && targetIndex >= 0
&& targetIndex !== originalIndex && dockApps)
dockApps.movePinnedApp(originalIndex, targetIndex)
if (dragging && targetIndex >= 0 && targetIndex !== originalIndex && dockApps) {
dockApps.movePinnedApp(originalIndex, targetIndex)
}
longPressing = false
dragging = false
@@ -184,10 +183,7 @@ Item {
}
onPositionChanged: mouse => {
if (longPressing && !dragging) {
var distance = Math.sqrt(
Math.pow(mouse.x - dragStartPos.x,
2) + Math.pow(
mouse.y - dragStartPos.y, 2))
const distance = Math.sqrt(Math.pow(mouse.x - dragStartPos.x, 2) + Math.pow(mouse.y - dragStartPos.y, 2))
if (distance > 5) {
dragging = true
targetIndex = index
@@ -195,79 +191,66 @@ Item {
}
}
if (dragging) {
dragOffset = Qt.point(
mouse.x - dragStartPos.x,
mouse.y - dragStartPos.y)
dragOffset = Qt.point(mouse.x - dragStartPos.x, mouse.y - dragStartPos.y)
if (dockApps) {
var threshold = 40
var newTargetIndex = targetIndex
if (dragOffset.x > threshold
&& targetIndex < dockApps.pinnedAppCount - 1)
newTargetIndex = targetIndex + 1
else if (dragOffset.x < -threshold
&& targetIndex > 0)
newTargetIndex = targetIndex - 1
const threshold = 40
let newTargetIndex = targetIndex
if (dragOffset.x > threshold && targetIndex < dockApps.pinnedAppCount - 1) {
newTargetIndex = targetIndex + 1
} else if (dragOffset.x < -threshold && targetIndex > 0) {
newTargetIndex = targetIndex - 1
}
if (newTargetIndex !== targetIndex) {
targetIndex = newTargetIndex
dragStartPos = Qt.point(mouse.x,
mouse.y)
dragStartPos = Qt.point(mouse.x, mouse.y)
}
}
}
}
onClicked: mouse => {
if (!appData || longPressing)
return
if (!appData || longPressing) {
return
}
if (mouse.button === Qt.LeftButton) {
// Handle based on type
if (appData.type === "pinned") {
// Launch the pinned app
if (appData && appData.appId) {
var desktopEntry = DesktopEntries.heuristicLookup(
appData.appId)
if (desktopEntry)
AppUsageHistoryData.addAppUsage({
"id": appData.appId,
"name": desktopEntry.name
|| appData.appId,
"icon": desktopEntry.icon
|| "",
"exec": desktopEntry.exec
|| "",
"comment": desktopEntry.comment || ""
})
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
if (desktopEntry) {
AppUsageHistoryData.addAppUsage({
"id": appData.appId,
"name": desktopEntry.name || appData.appId,
"icon": desktopEntry.icon || "",
"exec": desktopEntry.exec || "",
"comment": desktopEntry.comment || ""
})
}
desktopEntry.execute()
}
} else if (appData.type === "window") {
var toplevel = getToplevelObject()
const toplevel = getToplevelObject()
if (toplevel) {
toplevel.activate()
}
}
} else if (mouse.button === Qt.MiddleButton) {
if (appData && appData.appId) {
var desktopEntry = DesktopEntries.heuristicLookup(
appData.appId)
if (desktopEntry)
AppUsageHistoryData.addAppUsage({
"id": appData.appId,
"name": desktopEntry.name
|| appData.appId,
"icon": desktopEntry.icon
|| "",
"exec": desktopEntry.exec
|| "",
"comment": desktopEntry.comment
|| ""
})
desktopEntry.execute()
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
if (desktopEntry) {
AppUsageHistoryData.addAppUsage({
"id": appData.appId,
"name": desktopEntry.name || appData.appId,
"icon": desktopEntry.icon || "",
"exec": desktopEntry.exec || "",
"comment": desktopEntry.comment || ""
})
}
desktopEntry.execute()
}
} else if (mouse.button === Qt.RightButton) {
if (contextMenu)
contextMenu.showForButton(root, appData, 40)
if (contextMenu) {
contextMenu.showForButton(root, appData, 40)
}
}
}
}
@@ -278,8 +261,10 @@ Item {
anchors.centerIn: parent
implicitSize: 40
source: {
if (appData.appId === "__SEPARATOR__") return ""
var desktopEntry = DesktopEntries.heuristicLookup(Paths.moddedAppId(appData.appId))
if (appData.appId === "__SEPARATOR__") {
return ""
}
const desktopEntry = DesktopEntries.heuristicLookup(Paths.moddedAppId(appData.appId))
return desktopEntry && desktopEntry.icon ? Quickshell.iconPath(desktopEntry.icon, true) : ""
}
mipmap: true
@@ -301,12 +286,14 @@ Item {
Text {
anchors.centerIn: parent
text: {
if (!appData || !appData.appId)
if (!appData || !appData.appId) {
return "?"
}
var desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
if (desktopEntry && desktopEntry.name)
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
if (desktopEntry && desktopEntry.name) {
return desktopEntry.name.charAt(0).toUpperCase()
}
return appData.appId.charAt(0).toUpperCase()
}
@@ -326,17 +313,17 @@ Item {
radius: 1
visible: appData && (appData.isRunning || appData.type === "window")
color: {
if (!appData)
if (!appData) {
return "transparent"
}
// For window type, check if focused using reactive property
if (isWindowFocused)
if (isWindowFocused) {
return Theme.primary
}
// For running apps, show dimmer indicator
if (appData.isRunning || appData.type === "window")
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g,
Theme.surfaceText.b, 0.6)
if (appData.isRunning || appData.type === "window") {
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
}
return "transparent"
}

View File

@@ -17,15 +17,16 @@ Item {
implicitHeight: row.height
function movePinnedApp(fromIndex, toIndex) {
if (fromIndex === toIndex)
if (fromIndex === toIndex) {
return
}
var currentPinned = [...(SessionData.pinnedApps || [])]
if (fromIndex < 0 || fromIndex >= currentPinned.length || toIndex < 0
|| toIndex >= currentPinned.length)
const currentPinned = [...(SessionData.pinnedApps || [])]
if (fromIndex < 0 || fromIndex >= currentPinned.length || toIndex < 0 || toIndex >= currentPinned.length) {
return
}
var movedApp = currentPinned.splice(fromIndex, 1)[0]
const movedApp = currentPinned.splice(fromIndex, 1)[0]
currentPinned.splice(toIndex, 0, movedApp)
SessionData.setPinnedApps(currentPinned)
@@ -47,60 +48,48 @@ Item {
function updateModel() {
clear()
var items = []
var pinnedApps = [...(SessionData.pinnedApps || [])]
const items = []
const pinnedApps = [...(SessionData.pinnedApps || [])]
// First section: Pinned apps (always visible, not representing running windows)
pinnedApps.forEach(appId => {
items.push({
"type": "pinned",
"appId": appId,
"windowId": -1,
"windowTitle"// Use -1 instead of null to avoid ListModel warnings
: "",
"windowTitle": "",
"workspaceId": -1,
"isPinned"// Use -1 instead of null
: true,
"isRunning": false,
"isPinned": true,
"isRunning": false
})
})
root.pinnedAppCount = pinnedApps.length
// Get sorted toplevels from CompositorService
var sortedToplevels = CompositorService.sortedToplevels
// Add separator between pinned and running if both exist
if (pinnedApps.length > 0
&& sortedToplevels.length > 0) {
const sortedToplevels = CompositorService.sortedToplevels
if (pinnedApps.length > 0 && sortedToplevels.length > 0) {
items.push({
"type": "separator",
"appId": "__SEPARATOR__",
"windowId": -1,
"windowTitle"// Use -1 instead of null
: "",
"windowTitle": "",
"workspaceId": -1,
"isPinned"// Use -1 instead of null
: false,
"isPinned": false,
"isRunning": false,
"isFocused": false
})
}
// Second section: Running windows (sorted using Theme.sortToplevels)
sortedToplevels.forEach((toplevel, index) => {
// Limit window title length for tooltip
var title = toplevel.title || "(Unnamed)"
if (title.length > 50) {
title = title.substring(0, 47) + "..."
}
var uniqueId = toplevel.title + "|" + (toplevel.appId || "") + "|" + index
const title = toplevel.title || "(Unnamed)"
const truncatedTitle = title.length > 50 ? title.substring(0, 47) + "..." : title
const uniqueId = toplevel.title + "|" + (toplevel.appId || "") + "|" + index
items.push({
"type": "window",
"appId": toplevel.appId,
"windowId": index,
"windowTitle": title,
"windowTitle": truncatedTitle,
"workspaceId": -1,
"isPinned": false,
"isRunning": true,
@@ -108,9 +97,7 @@ Item {
})
})
items.forEach(item => {
append(item)
})
items.forEach(item => append(item))
}
}
@@ -125,8 +112,7 @@ Item {
visible: model.type === "separator"
width: 2
height: 20
color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.3)
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
radius: 1
anchors.centerIn: parent
}
@@ -159,8 +145,6 @@ Item {
}
}
Connections {
target: SessionData
function onPinnedAppsChanged() {

View File

@@ -21,10 +21,10 @@ PanelWindow {
appData = data
dockVisibleHeight = dockHeight || 40
var dockWindow = button.Window.window
const dockWindow = button.Window.window
if (dockWindow) {
for (var i = 0; i < Quickshell.screens.length; i++) {
var s = Quickshell.screens[i]
const s = Quickshell.screens[i]
if (dockWindow.x >= s.x && dockWindow.x < s.x + s.width) {
root.screen = s
break
@@ -55,8 +55,11 @@ PanelWindow {
property point anchorPos: Qt.point(screen.width / 2, screen.height - 100)
onAnchorItemChanged: updatePosition()
onVisibleChanged: if (visible)
updatePosition()
onVisibleChanged: {
if (visible) {
updatePosition()
}
}
function updatePosition() {
if (!anchorItem) {
@@ -64,40 +67,40 @@ PanelWindow {
return
}
var dockWindow = anchorItem.Window.window
const dockWindow = anchorItem.Window.window
if (!dockWindow) {
anchorPos = Qt.point(screen.width / 2, screen.height - 100)
return
}
var buttonPosInDock = anchorItem.mapToItem(dockWindow.contentItem, 0, 0)
var actualDockHeight = root.dockVisibleHeight // fallback
const buttonPosInDock = anchorItem.mapToItem(dockWindow.contentItem, 0, 0)
let actualDockHeight = root.dockVisibleHeight
function findDockBackground(item) {
if (item.objectName === "dockBackground") {
return item
}
for (var i = 0; i < item.children.length; i++) {
var found = findDockBackground(item.children[i])
if (found)
const found = findDockBackground(item.children[i])
if (found) {
return found
}
}
return null
}
var dockBackground = findDockBackground(dockWindow.contentItem)
const dockBackground = findDockBackground(dockWindow.contentItem)
if (dockBackground) {
actualDockHeight = dockBackground.height
}
var dockBottomMargin = 16 // The dock has bottom margin
var buttonScreenY = root.screen.height - actualDockHeight - dockBottomMargin - 20
const dockBottomMargin = 16
const buttonScreenY = root.screen.height - actualDockHeight - dockBottomMargin - 20
var dockContentWidth = dockWindow.width
var screenWidth = root.screen.width
var dockLeftMargin = Math.round((screenWidth - dockContentWidth) / 2)
var buttonScreenX = dockLeftMargin + buttonPosInDock.x + anchorItem.width / 2
const dockContentWidth = dockWindow.width
const screenWidth = root.screen.width
const dockLeftMargin = Math.round((screenWidth - dockContentWidth) / 2)
const buttonScreenX = dockLeftMargin + buttonPosInDock.x + anchorItem.width / 2
anchorPos = Qt.point(buttonScreenX, buttonScreenY)
}
@@ -105,22 +108,19 @@ PanelWindow {
Rectangle {
id: menuContainer
width: Math.min(400,
Math.max(200,
menuColumn.implicitWidth + Theme.spacingS * 2))
width: Math.min(400, Math.max(200, menuColumn.implicitWidth + Theme.spacingS * 2))
height: Math.max(60, menuColumn.implicitHeight + Theme.spacingS * 2)
x: {
var left = 10
var right = root.width - width - 10
var want = root.anchorPos.x - width / 2
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: Math.max(10, root.anchorPos.y - height + 30)
color: Theme.popupBackground()
radius: Theme.cornerRadius
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.08)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
opacity: showContextMenu ? 1 : 0
scale: showContextMenu ? 1 : 0.85
@@ -148,10 +148,7 @@ PanelWindow {
width: parent.width
height: 28
radius: Theme.cornerRadius
color: pinArea.containsMouse ? Qt.rgba(Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
color: pinArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
StyledText {
anchors.left: parent.left
@@ -159,8 +156,7 @@ PanelWindow {
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
text: root.appData
&& root.appData.isPinned ? "Unpin from Dock" : "Pin to Dock"
text: root.appData && root.appData.isPinned ? "Unpin from Dock" : "Pin to Dock"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Normal
@@ -174,8 +170,9 @@ PanelWindow {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (!root.appData)
if (!root.appData) {
return
}
if (root.appData.isPinned) {
SessionData.removePinnedApp(root.appData.appId)
} else {
@@ -190,16 +187,14 @@ PanelWindow {
visible: root.appData && root.appData.type === "window"
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
}
Rectangle {
visible: root.appData && root.appData.type === "window"
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
}
Rectangle {
@@ -207,11 +202,7 @@ PanelWindow {
width: parent.width
height: 28
radius: Theme.cornerRadius
color: closeArea.containsMouse ? Qt.rgba(
Theme.error.r,
Theme.error.g,
Theme.error.b,
0.12) : "transparent"
color: closeArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent"
StyledText {
anchors.left: parent.left

View File

@@ -38,10 +38,10 @@ Item {
}
onExited: (exitCode, exitStatus) => {
if (exitCode !== 0) {
console.warn("Failed to get session path, exit code:", exitCode)
}
}
if (exitCode !== 0) {
console.warn("Failed to get session path, exit code:", exitCode)
}
}
}
Process {
@@ -52,8 +52,7 @@ Item {
stdout: StdioCollector {
onStreamFinished: {
if (text.includes("true")) {
console.log(
"Session is locked on startup, activating lock screen")
console.log("Session is locked on startup, activating lock screen")
LockScreenService.resetState()
loader.activeAsync = true
}
@@ -61,11 +60,10 @@ Item {
}
onExited: (exitCode, exitStatus) => {
if (exitCode !== 0) {
console.warn("Failed to check initial lock state, exit code:",
exitCode)
}
}
if (exitCode !== 0) {
console.warn("Failed to check initial lock state, exit code:", exitCode)
}
}
}
Process {
@@ -77,32 +75,29 @@ Item {
splitMarker: "\n"
onRead: line => {
if (line.includes("org.freedesktop.login1.Session.Lock")) {
console.log("login1: Lock signal received -> show lock")
LockScreenService.resetState()
loader.activeAsync = true
} else if (line.includes(
"org.freedesktop.login1.Session.Unlock")) {
console.log("login1: Unlock signal received -> hide lock")
loader.active = false
} else if (line.includes("LockedHint") && line.includes(
"true")) {
console.log("login1: LockedHint=true -> show lock")
LockScreenService.resetState()
loader.activeAsync = true
} else if (line.includes("LockedHint") && line.includes(
"false")) {
console.log("login1: LockedHint=false -> hide lock")
loader.active = false
}
}
if (line.includes("org.freedesktop.login1.Session.Lock")) {
console.log("login1: Lock signal received -> show lock")
LockScreenService.resetState()
loader.activeAsync = true
} else if (line.includes("org.freedesktop.login1.Session.Unlock")) {
console.log("login1: Unlock signal received -> hide lock")
loader.active = false
} else if (line.includes("LockedHint") && line.includes("true")) {
console.log("login1: LockedHint=true -> show lock")
LockScreenService.resetState()
loader.activeAsync = true
} else if (line.includes("LockedHint") && line.includes("false")) {
console.log("login1: LockedHint=false -> hide lock")
loader.active = false
}
}
}
onExited: (exitCode, exitStatus) => {
if (exitCode !== 0) {
console.warn("gdbus monitor failed, exit code:", exitCode)
}
}
if (exitCode !== 0) {
console.warn("gdbus monitor failed, exit code:", exitCode)
}
}
}
LazyLoader {
@@ -117,8 +112,9 @@ Item {
locked: true
onLockedChanged: {
if (!locked)
loader.active = false
if (!locked) {
loader.active = false
}
}
LockSurface {
@@ -126,8 +122,8 @@ Item {
lock: sessionLock
sharedPasswordBuffer: sessionLock.sharedPasswordBuffer
onPasswordChanged: newPassword => {
sessionLock.sharedPasswordBuffer = newPassword
}
sessionLock.sharedPasswordBuffer = newPassword
}
}
}
}

View File

@@ -6,7 +6,6 @@ import Quickshell
import Quickshell.Io
import Quickshell.Services.Pam
import qs.Common
import qs.Modals
import qs.Services
import qs.Widgets
@@ -15,27 +14,47 @@ Item {
property string passwordBuffer: ""
property bool demoMode: false
property var powerModal: null
property string confirmAction: ""
signal unlockRequested
// Internal power dialog state
property bool powerDialogVisible: false
property string powerDialogTitle: ""
property string powerDialogMessage: ""
property string powerDialogConfirmText: ""
property color powerDialogConfirmColor: Theme.primary
property var powerDialogOnConfirm: function() {}
function showPowerDialog(title, message, confirmText, confirmColor, onConfirm) {
powerDialogTitle = title
powerDialogMessage = message
powerDialogConfirmText = confirmText
powerDialogConfirmColor = confirmColor
powerDialogOnConfirm = onConfirm
powerDialogVisible = true
}
function hidePowerDialog() {
powerDialogVisible = false
}
Component.onCompleted: {
if (demoMode)
if (demoMode) {
LockScreenService.pickRandomFact()
}
WeatherService.addRef()
UserInfoService.refreshUserInfo()
}
onDemoModeChanged: {
if (demoMode)
if (demoMode) {
LockScreenService.pickRandomFact()
}
}
Component.onDestruction: {
WeatherService.removeRef()
}
// Backdrop for when no wallpaper is set
Loader {
anchors.fill: parent
active: !SessionData.wallpaperPath
@@ -159,11 +178,13 @@ Item {
id: profileImageLoader
source: {
if (PortalService.profileImage === "")
if (PortalService.profileImage === "") {
return ""
}
if (PortalService.profileImage.startsWith("/"))
if (PortalService.profileImage.startsWith("/")) {
return "file://" + PortalService.profileImage
}
return PortalService.profileImage
}
@@ -221,8 +242,7 @@ Item {
name: "warning"
size: Theme.iconSize + 4
color: Theme.primaryText
visible: PortalService.profileImage !== ""
&& profileImageLoader.status === Image.Error
visible: PortalService.profileImage !== "" && profileImageLoader.status === Image.Error
}
}
@@ -232,11 +252,8 @@ Item {
Layout.fillWidth: true
Layout.preferredHeight: 60
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r,
Theme.surfaceContainer.g,
Theme.surfaceContainer.b, 0.9)
border.color: passwordField.activeFocus ? Theme.primary : Qt.rgba(
1, 1, 1, 0.3)
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9)
border.color: passwordField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3)
border.width: passwordField.activeFocus ? 2 : 1
DankIcon {
@@ -255,29 +272,44 @@ Item {
anchors.fill: parent
anchors.leftMargin: lockIcon.width + Theme.spacingM * 2
anchors.rightMargin: (revealButton.visible ? revealButton.width : 0) + (virtualKeyboardButton.visible ? virtualKeyboardButton.width : 0) + (enterButton.visible ? enterButton.width + 2 : 0) + (loadingSpinner.visible ? loadingSpinner.width + Theme.spacingM : Theme.spacingM)
anchors.rightMargin: {
let margin = Theme.spacingM
if (loadingSpinner.visible) {
margin += loadingSpinner.width
}
if (enterButton.visible) {
margin += enterButton.width + 2
}
if (virtualKeyboardButton.visible) {
margin += virtualKeyboardButton.width
}
if (revealButton.visible) {
margin += revealButton.width
}
return margin
}
opacity: 0
focus: !demoMode
enabled: !demoMode
echoMode: parent.showPassword ? TextInput.Normal : TextInput.Password
onTextChanged: {
if (!demoMode)
if (!demoMode) {
root.passwordBuffer = text
}
}
onAccepted: {
if (!demoMode && root.passwordBuffer.length > 0
&& !pam.active) {
if (!demoMode && root.passwordBuffer.length > 0 && !pam.active) {
console.log("Enter pressed, starting PAM authentication")
pam.start()
}
}
Keys.onPressed: event => {
if (demoMode)
return
if (demoMode) {
return
}
if (pam.active) {
console.log(
"PAM is active, ignoring input")
console.log("PAM is active, ignoring input")
event.accepted = true
return
}
@@ -292,38 +324,35 @@ Item {
}
}
KeyboardController {
id: keyboardController
target: passwordField
rootObject: root
}
KeyboardController {
id: keyboardController
target: passwordField
rootObject: root
}
StyledText {
id: placeholder
property string pamState: ""
anchors.left: lockIcon.right
anchors.leftMargin: Theme.spacingM
anchors.right: (revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right))))
anchors.rightMargin: 2
anchors.verticalCenter: parent.verticalCenter
text: {
if (demoMode)
if (demoMode) {
return ""
if (LockScreenService.unlocking)
}
if (LockScreenService.unlocking) {
return "Unlocking..."
if (pam.active)
}
if (pam.active) {
return "Authenticating..."
}
return "Password..."
}
color: LockScreenService.unlocking ? Theme.primary : (pam.active ? Theme.primary : Theme.outline)
font.pixelSize: Theme.fontSizeMedium
opacity: (demoMode
|| root.passwordBuffer.length === 0) ? 1 : 0
opacity: (demoMode || root.passwordBuffer.length === 0) ? 1 : 0
Behavior on opacity {
NumberAnimation {
@@ -347,19 +376,17 @@ Item {
anchors.rightMargin: 2
anchors.verticalCenter: parent.verticalCenter
text: {
if (demoMode)
if (demoMode) {
return "••••••••"
else if (parent.showPassword)
}
if (parent.showPassword) {
return root.passwordBuffer
else
return "•".repeat(
Math.min(
root.passwordBuffer.length, 25))
}
return "•".repeat(Math.min(root.passwordBuffer.length, 25))
}
color: Theme.surfaceText
font.pixelSize: parent.showPassword ? Theme.fontSizeMedium : Theme.fontSizeLarge
opacity: (demoMode
|| root.passwordBuffer.length > 0) ? 1 : 0
opacity: (demoMode || root.passwordBuffer.length > 0) ? 1 : 0
elide: Text.ElideRight
Behavior on opacity {
@@ -378,12 +405,11 @@ Item {
anchors.verticalCenter: parent.verticalCenter
iconName: parent.showPassword ? "visibility_off" : "visibility"
buttonSize: 32
visible: !demoMode && root.passwordBuffer.length > 0
&& !pam.active && !LockScreenService.unlocking
visible: !demoMode && root.passwordBuffer.length > 0 && !pam.active && !LockScreenService.unlocking
enabled: visible
onClicked: parent.showPassword = !parent.showPassword
}
DankActionButton {
DankActionButton {
id: virtualKeyboardButton
anchors.right: enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right)
@@ -393,15 +419,12 @@ Item {
buttonSize: 32
visible: !demoMode && !pam.active && !LockScreenService.unlocking
enabled: visible
onClicked:
{
if(keyboardController.isKeyboardActive)
{
onClicked: {
if (keyboardController.isKeyboardActive) {
keyboardController.hide()
} else
{
keyboardController.show()
}
} else {
keyboardController.show()
}
}
}
@@ -415,8 +438,7 @@ Item {
height: 24
radius: 12
color: "transparent"
visible: !demoMode && (pam.active
|| LockScreenService.unlocking)
visible: !demoMode && (pam.active || LockScreenService.unlocking)
DankIcon {
anchors.centerIn: parent
@@ -456,9 +478,7 @@ Item {
radius: 10
anchors.centerIn: parent
color: "transparent"
border.color: Qt.rgba(Theme.primary.r,
Theme.primary.g,
Theme.primary.b, 0.3)
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3)
border.width: 2
}
@@ -476,15 +496,11 @@ Item {
height: parent.height / 2
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
color: Qt.rgba(Theme.surfaceContainer.r,
Theme.surfaceContainer.g,
Theme.surfaceContainer.b,
0.9)
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9)
}
RotationAnimation on rotation {
running: pam.active
&& !LockScreenService.unlocking
running: pam.active && !LockScreenService.unlocking
loops: Animation.Infinite
duration: Anims.durLong
from: 0
@@ -502,9 +518,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
iconName: "keyboard_return"
buttonSize: 36
visible: (demoMode || (root.passwordBuffer.length > 0
&& !pam.active
&& !LockScreenService.unlocking))
visible: (demoMode || (root.passwordBuffer.length > 0 && !pam.active && !LockScreenService.unlocking))
enabled: !demoMode
onClicked: {
if (!demoMode) {
@@ -534,15 +548,15 @@ Item {
Layout.fillWidth: true
Layout.preferredHeight: LockScreenService.pamState ? 20 : 0
text: {
if (LockScreenService.pamState === "error")
if (LockScreenService.pamState === "error") {
return "Authentication error - try again"
if (LockScreenService.pamState === "max")
}
if (LockScreenService.pamState === "max") {
return "Too many attempts - locked out"
if (LockScreenService.pamState === "fail")
}
if (LockScreenService.pamState === "fail") {
return "Incorrect password - try again"
}
return ""
}
color: Theme.error
@@ -578,22 +592,19 @@ Item {
visible: demoMode
}
// Status bar at top
Row {
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: Theme.spacingXL
spacing: Theme.spacingL
// Weather section
Row {
spacing: 6
visible: WeatherService.weather.available
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: WeatherService.getWeatherIcon(
WeatherService.weather.wCode)
name: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
size: Theme.iconSize
color: "white"
anchors.verticalCenter: parent.verticalCenter
@@ -608,91 +619,63 @@ Item {
}
}
// Separator
Rectangle {
width: 1
height: 24
color: Qt.rgba(255, 255, 255, 0.2)
anchors.verticalCenter: parent.verticalCenter
visible: WeatherService.weather.available
&& (NetworkService.networkStatus !== "disconnected"
|| BluetoothService.enabled
|| (AudioService.sink && AudioService.sink.audio)
|| BatteryService.batteryAvailable)
visible: WeatherService.weather.available && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio) || BatteryService.batteryAvailable)
}
// System status icons
Row {
spacing: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
visible: NetworkService.networkStatus !== "disconnected"
|| (BluetoothService.available
&& BluetoothService.enabled)
|| (AudioService.sink && AudioService.sink.audio)
visible: NetworkService.networkStatus !== "disconnected" || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio)
// Network icon
DankIcon {
name: {
if (NetworkService.networkStatus === "ethernet") {
return "lan"
}
return NetworkService.wifiSignalIcon
}
name: NetworkService.networkStatus === "ethernet" ? "lan" : NetworkService.wifiSignalIcon
size: Theme.iconSize - 2
color: NetworkService.networkStatus
!== "disconnected" ? "white" : Qt.rgba(255,
255, 255, 0.5)
color: NetworkService.networkStatus !== "disconnected" ? "white" : Qt.rgba(255, 255, 255, 0.5)
anchors.verticalCenter: parent.verticalCenter
visible: NetworkService.networkStatus !== "disconnected"
}
// Bluetooth icon
DankIcon {
name: "bluetooth"
size: Theme.iconSize - 2
color: "white"
anchors.verticalCenter: parent.verticalCenter
visible: BluetoothService.available
&& BluetoothService.enabled
visible: BluetoothService.available && BluetoothService.enabled
}
// Volume icon
DankIcon {
name: {
if (AudioService.sink && AudioService.sink.audio) {
if (AudioService.sink.audio.muted
|| AudioService.sink.audio.volume === 0)
return "volume_off"
else if (AudioService.sink.audio.volume * 100 < 33)
return "volume_down"
else
return "volume_up"
if (!AudioService.sink?.audio) {
return "volume_up"
}
if (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0) {
return "volume_off"
}
if (AudioService.sink.audio.volume * 100 < 33) {
return "volume_down"
}
return "volume_up"
}
size: Theme.iconSize - 2
color: (AudioService.sink && AudioService.sink.audio
&& (AudioService.sink.audio.muted
|| AudioService.sink.audio.volume
=== 0)) ? Qt.rgba(255, 255, 255, 0.5) : "white"
color: (AudioService.sink && AudioService.sink.audio && (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0)) ? Qt.rgba(255, 255, 255, 0.5) : "white"
anchors.verticalCenter: parent.verticalCenter
visible: AudioService.sink && AudioService.sink.audio
}
}
// Separator
Rectangle {
width: 1
height: 24
color: Qt.rgba(255, 255, 255, 0.2)
anchors.verticalCenter: parent.verticalCenter
visible: BatteryService.batteryAvailable
&& (NetworkService.networkStatus !== "disconnected"
|| BluetoothService.enabled
|| (AudioService.sink && AudioService.sink.audio))
visible: BatteryService.batteryAvailable && (NetworkService.networkStatus !== "disconnected" || BluetoothService.enabled || (AudioService.sink && AudioService.sink.audio))
}
// Battery section
Row {
spacing: 4
visible: BatteryService.batteryAvailable
@@ -701,78 +684,94 @@ Item {
DankIcon {
name: {
if (BatteryService.isCharging) {
if (BatteryService.batteryLevel >= 90)
if (BatteryService.batteryLevel >= 90) {
return "battery_charging_full"
}
if (BatteryService.batteryLevel >= 80)
if (BatteryService.batteryLevel >= 80) {
return "battery_charging_90"
}
if (BatteryService.batteryLevel >= 60)
if (BatteryService.batteryLevel >= 60) {
return "battery_charging_80"
}
if (BatteryService.batteryLevel >= 50)
if (BatteryService.batteryLevel >= 50) {
return "battery_charging_60"
}
if (BatteryService.batteryLevel >= 30)
if (BatteryService.batteryLevel >= 30) {
return "battery_charging_50"
}
if (BatteryService.batteryLevel >= 20)
if (BatteryService.batteryLevel >= 20) {
return "battery_charging_30"
}
return "battery_charging_20"
}
// Check if plugged in but not charging (like at 80% charge limit)
if (BatteryService.isPluggedIn) {
if (BatteryService.batteryLevel >= 90)
if (BatteryService.batteryLevel >= 90) {
return "battery_charging_full"
}
if (BatteryService.batteryLevel >= 80)
if (BatteryService.batteryLevel >= 80) {
return "battery_charging_90"
}
if (BatteryService.batteryLevel >= 60)
if (BatteryService.batteryLevel >= 60) {
return "battery_charging_80"
}
if (BatteryService.batteryLevel >= 50)
if (BatteryService.batteryLevel >= 50) {
return "battery_charging_60"
}
if (BatteryService.batteryLevel >= 30)
if (BatteryService.batteryLevel >= 30) {
return "battery_charging_50"
}
if (BatteryService.batteryLevel >= 20)
if (BatteryService.batteryLevel >= 20) {
return "battery_charging_30"
}
return "battery_charging_20"
}
// On battery power
if (BatteryService.batteryLevel >= 95)
if (BatteryService.batteryLevel >= 95) {
return "battery_full"
}
if (BatteryService.batteryLevel >= 85)
if (BatteryService.batteryLevel >= 85) {
return "battery_6_bar"
}
if (BatteryService.batteryLevel >= 70)
if (BatteryService.batteryLevel >= 70) {
return "battery_5_bar"
}
if (BatteryService.batteryLevel >= 55)
if (BatteryService.batteryLevel >= 55) {
return "battery_4_bar"
}
if (BatteryService.batteryLevel >= 40)
if (BatteryService.batteryLevel >= 40) {
return "battery_3_bar"
}
if (BatteryService.batteryLevel >= 25)
if (BatteryService.batteryLevel >= 25) {
return "battery_2_bar"
}
return "battery_1_bar"
}
size: Theme.iconSize
color: {
if (BatteryService.isLowBattery
&& !BatteryService.isCharging)
if (BatteryService.isLowBattery && !BatteryService.isCharging) {
return Theme.error
}
if (BatteryService.isCharging
|| BatteryService.isPluggedIn)
if (BatteryService.isCharging || BatteryService.isPluggedIn) {
return Theme.primary
}
return "white"
}
@@ -800,10 +799,13 @@ Item {
iconColor: Theme.error
buttonSize: 40
onClicked: {
if (demoMode)
if (demoMode) {
console.log("Demo: Power")
else
LockScreenService.showPowerDialog()
} else {
showPowerDialog("Power Off", "Power off this computer?", "Power Off", Theme.error, function() {
SessionService.poweroff()
})
}
}
}
@@ -811,10 +813,13 @@ Item {
iconName: "refresh"
buttonSize: 40
onClicked: {
if (demoMode)
if (demoMode) {
console.log("Demo: Reboot")
else
LockScreenService.showRebootDialog()
} else {
showPowerDialog("Restart", "Restart this computer?", "Restart", Theme.primary, function() {
SessionService.reboot()
})
}
}
}
@@ -822,10 +827,13 @@ Item {
iconName: "logout"
buttonSize: 40
onClicked: {
if (demoMode)
if (demoMode) {
console.log("Demo: Logout")
else
LockScreenService.showLogoutDialog()
} else {
showPowerDialog("Log Out", "End this session?", "Log Out", Theme.primary, function() {
SessionService.logout()
})
}
}
}
}
@@ -864,16 +872,14 @@ Item {
if (!responseRequired)
return
console.log("Responding to PAM with password buffer length:",
root.passwordBuffer.length)
console.log("Responding to PAM with password buffer length:", root.passwordBuffer.length)
respond(root.passwordBuffer)
}
onCompleted: res => {
if (demoMode)
return
console.log(
"PAM authentication completed with result:", res)
console.log("PAM authentication completed with result:", res)
if (res === PamResult.Success) {
console.log("Authentication successful, unlocking")
LockScreenService.setUnlocking(true)
@@ -906,20 +912,11 @@ Item {
onClicked: root.unlockRequested()
}
// Internal power dialog
Rectangle {
id: powerDialog
function open() {
LockScreenService.showPowerDialog()
}
function close() {
LockScreenService.hidePowerDialog()
}
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.8)
visible: LockScreenService.powerDialogVisible
visible: powerDialogVisible
z: 1000
Rectangle {
@@ -939,12 +936,12 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
name: "power_settings_new"
size: 32
color: Theme.error
color: powerDialogConfirmColor
}
StyledText {
anchors.horizontalCenter: parent.horizontalCenter
text: "Power off this computer?"
text: powerDialogMessage
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
@@ -958,11 +955,7 @@ Item {
width: 100
height: 40
radius: Theme.cornerRadius
color: cancelMouse1.pressed ? Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
0.7) : cancelMouse1.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.9) : Theme.surfaceVariant
color: Theme.surfaceVariant
StyledText {
anchors.centerIn: parent
@@ -972,12 +965,10 @@ Item {
}
MouseArea {
id: cancelMouse1
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: powerDialog.close()
onClicked: hidePowerDialog()
}
}
@@ -985,249 +976,23 @@ Item {
width: 100
height: 40
radius: Theme.cornerRadius
color: powerMouse.pressed ? Qt.rgba(
Theme.error.r,
Theme.error.g,
Theme.error.b,
0.8) : powerMouse.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 1) : Theme.error
color: powerDialogConfirmColor
StyledText {
anchors.centerIn: parent
text: "Power Off"
color: "white"
text: powerDialogConfirmText
color: Theme.primaryText
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
}
MouseArea {
id: powerMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
powerDialog.close()
SessionService.poweroff()
}
}
}
}
}
}
}
Rectangle {
id: rebootDialog
function open() {
LockScreenService.showRebootDialog()
}
function close() {
LockScreenService.hideRebootDialog()
}
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.8)
visible: LockScreenService.rebootDialogVisible
z: 1000
Rectangle {
anchors.centerIn: parent
width: 320
height: 180
radius: Theme.cornerRadius
color: Theme.surfaceContainer
border.color: Theme.outline
border.width: 1
Column {
anchors.centerIn: parent
spacing: Theme.spacingXL
DankIcon {
anchors.horizontalCenter: parent.horizontalCenter
name: "refresh"
size: 32
color: Theme.primary
}
StyledText {
anchors.horizontalCenter: parent.horizontalCenter
text: "Restart this computer?"
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM
Rectangle {
width: 100
height: 40
radius: Theme.cornerRadius
color: cancelMouse2.pressed ? Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
0.7) : cancelMouse2.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.9) : Theme.surfaceVariant
StyledText {
anchors.centerIn: parent
text: "Cancel"
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium
}
MouseArea {
id: cancelMouse2
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: rebootDialog.close()
}
}
Rectangle {
width: 100
height: 40
radius: Theme.cornerRadius
color: rebootMouse.pressed ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.8) : rebootMouse.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 1) : Theme.primary
StyledText {
anchors.centerIn: parent
text: "Restart"
color: "white"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
}
MouseArea {
id: rebootMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
rebootDialog.close()
SessionService.reboot()
}
}
}
}
}
}
}
Rectangle {
id: logoutDialog
function open() {
LockScreenService.showLogoutDialog()
}
function close() {
LockScreenService.hideLogoutDialog()
}
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.8)
visible: LockScreenService.logoutDialogVisible
z: 1000
Rectangle {
anchors.centerIn: parent
width: 320
height: 180
radius: Theme.cornerRadius
color: Theme.surfaceContainer
border.color: Theme.outline
border.width: 1
Column {
anchors.centerIn: parent
spacing: Theme.spacingXL
DankIcon {
anchors.horizontalCenter: parent.horizontalCenter
name: "logout"
size: 32
color: Theme.primary
}
StyledText {
anchors.horizontalCenter: parent.horizontalCenter
text: "End this session?"
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM
Rectangle {
width: 100
height: 40
radius: Theme.cornerRadius
color: cancelMouse3.pressed ? Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
0.7) : cancelMouse3.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.9) : Theme.surfaceVariant
StyledText {
anchors.centerIn: parent
text: "Cancel"
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium
}
MouseArea {
id: cancelMouse3
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: logoutDialog.close()
}
}
Rectangle {
width: 100
height: 40
radius: Theme.cornerRadius
color: logoutMouse.pressed ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.8) : logoutMouse.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 1) : Theme.primary
StyledText {
anchors.centerIn: parent
text: "Log Out"
color: "white"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
}
MouseArea {
id: logoutMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
logoutDialog.close()
SessionService.logout()
hidePowerDialog()
powerDialogOnConfirm()
}
}
}

View File

@@ -2,7 +2,6 @@ import QtQuick
import Quickshell
import Quickshell.Wayland
import qs.Common
import qs.Modals.Common
PanelWindow {
id: root
@@ -34,16 +33,11 @@ PanelWindow {
demoActive = false
}
ConfirmModal {
id: powerModal
}
Loader {
anchors.fill: parent
active: demoActive
sourceComponent: LockScreenContent {
demoMode: true
powerModal: powerModal
onUnlockRequested: root.hideDemo()
}
}

View File

@@ -1,8 +1,8 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import qs.Common
import qs.Modals.Common
WlSessionLockSurface {
id: root
@@ -20,15 +20,10 @@ WlSessionLockSurface {
color: "transparent"
ConfirmModal {
id: powerConfirmModal
}
Loader {
anchors.fill: parent
sourceComponent: LockScreenContent {
demoMode: false
powerModal: powerConfirmModal
passwordBuffer: root.sharedPasswordBuffer
onUnlockRequested: root.unlock()
onPasswordBufferChanged: {