1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-07 14:05:38 -05:00

Code cleanups and some keyboard navigation on AppLauncher

This commit is contained in:
bbedward
2025-07-12 22:47:39 -04:00
parent f843d4dc7b
commit 44f6f3ca1a
8 changed files with 99 additions and 202 deletions

View File

@@ -1,105 +0,0 @@
import QtQuick
import QtCore
import Quickshell
import Quickshell.Io
pragma Singleton
pragma ComponentBehavior: Bound
Singleton {
id: root
property string configDir: StandardPaths.writableLocation(StandardPaths.ConfigLocation) + "/DankMaterialShell"
property string recentAppsFile: configDir + "/recentApps.json"
property int maxRecentApps: 10
property var recentApps: []
// Create config directory on startup
Process {
id: mkdirProcess
command: ["mkdir", "-p", root.configDir]
running: true
onExited: {
loadRecentApps()
}
}
FileView {
id: recentAppsFileView
path: root.recentAppsFile
onTextChanged: {
if (text && text.length > 0) {
try {
var data = JSON.parse(text)
if (Array.isArray(data)) {
root.recentApps = data
}
} catch (e) {
console.log("PreferencesService: Invalid recent apps format")
root.recentApps = []
}
}
}
}
function loadRecentApps() {
// FileView will automatically load and trigger onTextChanged
if (!recentAppsFileView.text || recentAppsFileView.text.length === 0) {
recentApps = []
}
}
function saveRecentApps() {
var jsonData = JSON.stringify(recentApps, null, 2)
var process = Qt.createQmlObject('
import Quickshell.Io
Process {
command: ["sh", "-c", "echo \'' + jsonData.replace(/'/g, "'\"'\"'") + '\' > \'' + root.recentAppsFile + '\'"]
running: true
onExited: {
if (exitCode !== 0) {
console.warn("Failed to save recent apps:", exitCode)
}
destroy()
}
}
', root)
}
function addRecentApp(app) {
if (!app) return
var execProp = app.execString || ""
if (!execProp) return
// Create a minimal app object to store
var appData = {
name: app.name,
exec: execProp,
icon: app.icon || "application-x-executable",
comment: app.comment || ""
}
// Remove existing entry if present
recentApps = recentApps.filter(a => a.exec !== execProp)
// Add to front
recentApps.unshift(appData)
// Limit size
if (recentApps.length > maxRecentApps) {
recentApps = recentApps.slice(0, maxRecentApps)
}
saveRecentApps()
}
function getRecentApps() {
return recentApps
}
function clearRecentApps() {
recentApps = []
saveRecentApps()
}
}

View File

@@ -9,7 +9,6 @@ singleton BrightnessService 1.0 BrightnessService.qml
singleton BatteryService 1.0 BatteryService.qml
singleton SystemMonitorService 1.0 SystemMonitorService.qml
singleton AppSearchService 1.0 AppSearchService.qml
singleton PreferencesService 1.0 PreferencesService.qml
singleton LauncherService 1.0 LauncherService.qml
singleton NiriWorkspaceService 1.0 NiriWorkspaceService.qml
singleton CalendarService 1.0 CalendarService.qml

View File

@@ -37,6 +37,7 @@ PanelWindow {
property var pinnedApps: ["firefox", "code", "terminal", "file-manager"]
property bool showCategories: false
property string viewMode: "list" // "list" or "grid"
property int selectedIndex: 0
ListModel { id: filteredModel }
@@ -95,6 +96,7 @@ PanelWindow {
function updateFilteredModel() {
filteredModel.clear()
selectedIndex = 0
var apps = []
@@ -131,6 +133,57 @@ PanelWindow {
})
})
}
function selectNext() {
if (filteredModel.count > 0) {
if (viewMode === "grid") {
// Grid navigation: move by columns
var columnsCount = appGrid.columnsCount || 8
selectedIndex = Math.min(selectedIndex + columnsCount, filteredModel.count - 1)
} else {
// List navigation: next item
selectedIndex = (selectedIndex + 1) % filteredModel.count
}
}
}
function selectPrevious() {
if (filteredModel.count > 0) {
if (viewMode === "grid") {
// Grid navigation: move by columns
var columnsCount = appGrid.columnsCount || 8
selectedIndex = Math.max(selectedIndex - columnsCount, 0)
} else {
// List navigation: previous item
selectedIndex = selectedIndex > 0 ? selectedIndex - 1 : filteredModel.count - 1
}
}
}
function selectNextInRow() {
if (filteredModel.count > 0 && viewMode === "grid") {
selectedIndex = Math.min(selectedIndex + 1, filteredModel.count - 1)
}
}
function selectPreviousInRow() {
if (filteredModel.count > 0 && viewMode === "grid") {
selectedIndex = Math.max(selectedIndex - 1, 0)
}
}
function launchSelected() {
if (filteredModel.count > 0 && selectedIndex >= 0 && selectedIndex < filteredModel.count) {
var selectedApp = filteredModel.get(selectedIndex)
if (selectedApp.desktopEntry) {
Prefs.addRecentApp(selectedApp.desktopEntry)
AppSearchService.launchApp(selectedApp.desktopEntry)
} else {
launcher.launchApp(selectedApp.exec)
}
launcher.hide()
}
}
Component {
id: iconComponent
@@ -277,6 +330,21 @@ PanelWindow {
if (event.key === Qt.Key_Escape) {
launcher.hide()
event.accepted = true
} else if (event.key === Qt.Key_Down) {
selectNext()
event.accepted = true
} else if (event.key === Qt.Key_Up) {
selectPrevious()
event.accepted = true
} else if (event.key === Qt.Key_Right && viewMode === "grid") {
selectNextInRow()
event.accepted = true
} else if (event.key === Qt.Key_Left && viewMode === "grid") {
selectPreviousInRow()
event.accepted = true
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
launchSelected()
event.accepted = true
}
}
@@ -559,6 +627,7 @@ PanelWindow {
model: filteredModel
delegate: listDelegate
currentIndex: selectedIndex
// Make mouse wheel scrolling more responsive
property real wheelStepSize: 60
@@ -566,6 +635,8 @@ PanelWindow {
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
propagateComposedEvents: true
z: -1
onWheel: (wheel) => {
var delta = wheel.angleDelta.y
@@ -618,6 +689,8 @@ PanelWindow {
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
propagateComposedEvents: true
z: -1
onWheel: (wheel) => {
var delta = wheel.angleDelta.y
@@ -689,6 +762,8 @@ PanelWindow {
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
propagateComposedEvents: true
z: -1
onWheel: (wheel) => {
var delta = wheel.angleDelta.y
@@ -746,10 +821,12 @@ PanelWindow {
width: appList.width
height: 72
radius: Theme.cornerRadiusLarge
color: appMouseArea.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
color: ListView.isCurrentItem ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) :
appMouseArea.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) :
Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
border.color: ListView.isCurrentItem ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) :
Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: ListView.isCurrentItem ? 2 : 1
Row {
anchors.fill: parent
@@ -799,6 +876,9 @@ PanelWindow {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
z: 10
property bool hovered: containsMouse
onEntered: selectedIndex = index
onClicked: {
if (model.desktopEntry) {
Prefs.addRecentApp(model.desktopEntry)
@@ -819,10 +899,12 @@ PanelWindow {
width: appGrid.cellWidth - 8
height: appGrid.cellHeight - 8
radius: Theme.cornerRadiusLarge
color: gridAppArea.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
color: selectedIndex === index ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) :
gridAppArea.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) :
Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
border.color: selectedIndex === index ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) :
Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: selectedIndex === index ? 2 : 1
Column {
anchors.centerIn: parent
@@ -861,6 +943,9 @@ PanelWindow {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
z: 10
property bool hovered: containsMouse
onEntered: selectedIndex = index
onClicked: {
if (model.desktopEntry) {
Prefs.addRecentApp(model.desktopEntry)

View File

@@ -1,5 +1,4 @@
import QtQuick
import QtQuick.Controls
import "../Common"
import "../Services"
@@ -65,7 +64,6 @@ Rectangle {
onClicked: {
batteryPopupVisible = !batteryPopupVisible
root.batteryPopupVisible = batteryPopupVisible
}
}

View File

@@ -1,74 +0,0 @@
import QtQuick
import QtQuick.Controls
import "../Common"
Rectangle {
id: powerButton
width: 48
height: 30
radius: Theme.cornerRadius
color: powerArea.containsMouse || root.powerMenuVisible ?
Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.16) :
Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
// Power icon
Text {
text: "power_settings_new"
font.family: Theme.iconFont
font.pixelSize: Theme.iconSize - 6
color: powerArea.containsMouse || root.powerMenuVisible ? Theme.error : Theme.surfaceText
anchors.centerIn: parent
}
MouseArea {
id: powerArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.powerMenuVisible = !root.powerMenuVisible
}
}
// Tooltip on hover
Rectangle {
id: powerTooltip
width: tooltipText.contentWidth + Theme.spacingM * 2
height: tooltipText.contentHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainer
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
visible: powerArea.containsMouse && !root.powerMenuVisible
anchors.bottom: parent.top
anchors.bottomMargin: Theme.spacingS
anchors.horizontalCenter: parent.horizontalCenter
opacity: powerArea.containsMouse ? 1.0 : 0.0
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Text {
id: tooltipText
text: "Power Menu"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.centerIn: parent
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

@@ -499,6 +499,8 @@ PanelWindow {
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
propagateComposedEvents: true
z: -1
onWheel: (wheel) => {
var delta = wheel.angleDelta.y
@@ -569,6 +571,7 @@ PanelWindow {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
z: 10
onEntered: selectedIndex = index
onClicked: launchApp(model)
}
@@ -611,6 +614,8 @@ PanelWindow {
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
propagateComposedEvents: true
z: -1
onWheel: (wheel) => {
var delta = wheel.angleDelta.y
@@ -679,6 +684,7 @@ PanelWindow {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
z: 10
onEntered: selectedIndex = index
onClicked: launchApp(model)
}

View File

@@ -68,17 +68,6 @@ PanelWindow {
property int count: 0
}
// Battery widget and other widgets are imported from their original locations
// These will be handled by the parent shell
property alias batteryWidget: batteryWidgetProxy
property alias cpuMonitorWidget: cpuMonitorWidgetProxy
property alias ramMonitorWidget: ramMonitorWidgetProxy
property alias powerButton: powerButtonProxy
QtObject { id: batteryWidgetProxy }
QtObject { id: cpuMonitorWidgetProxy }
QtObject { id: ramMonitorWidgetProxy }
QtObject { id: powerButtonProxy }
anchors {
top: true

View File

@@ -9,7 +9,6 @@ CustomSlider 1.0 CustomSlider.qml
InputDialog 1.0 InputDialog.qml
BatteryWidget 1.0 BatteryWidget.qml
BatteryControlPopup 1.0 BatteryControlPopup.qml
PowerButton 1.0 PowerButton.qml
PowerMenuPopup 1.0 PowerMenuPopup.qml
PowerConfirmDialog 1.0 PowerConfirmDialog.qml
ThemePicker 1.0 ThemePicker.qml