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:
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -132,6 +134,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
|
||||
Item {
|
||||
@@ -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)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import "../Common"
|
||||
import "../Services"
|
||||
|
||||
@@ -65,7 +64,6 @@ Rectangle {
|
||||
|
||||
onClicked: {
|
||||
batteryPopupVisible = !batteryPopupVisible
|
||||
root.batteryPopupVisible = batteryPopupVisible
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user