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

Make recent apps a category

This commit is contained in:
bbedward
2025-07-12 22:00:40 -04:00
parent 2e94cf26a7
commit e6821a73a5
3 changed files with 62 additions and 208 deletions

View File

@@ -158,9 +158,9 @@ Singleton {
return a.name.localeCompare(b.name) // Alphabetical tiebreaker return a.name.localeCompare(b.name) // Alphabetical tiebreaker
}) })
// Limit to 5 apps // Limit to 10 apps
if (sortedApps.length > 5) { if (sortedApps.length > 10) {
sortedApps = sortedApps.slice(0, 5) sortedApps = sortedApps.slice(0, 10)
} }
// Reassign to trigger property change signal // Reassign to trigger property change signal

View File

@@ -65,7 +65,9 @@ PanelWindow {
target: AppSearchService target: AppSearchService
function onReadyChanged() { function onReadyChanged() {
if (AppSearchService.ready) { if (AppSearchService.ready) {
categories = AppSearchService.getAllCategories() var allCategories = AppSearchService.getAllCategories()
// Insert "Recents" after "All"
categories = ["All", "Recents"].concat(allCategories.filter(cat => cat !== "All"))
updateFilteredModel() updateFilteredModel()
} }
} }
@@ -101,13 +103,20 @@ PanelWindow {
// Search across all apps or category // Search across all apps or category
var baseApps = selectedCategory === "All" ? var baseApps = selectedCategory === "All" ?
AppSearchService.applications : AppSearchService.applications :
AppSearchService.getAppsInCategory(selectedCategory) selectedCategory === "Recents" ?
recentApps.map(recentApp => AppSearchService.getAppByExec(recentApp.exec)).filter(app => app !== null) :
AppSearchService.getAppsInCategory(selectedCategory)
apps = AppSearchService.searchApplications(searchField.text).filter(app => apps = AppSearchService.searchApplications(searchField.text).filter(app =>
baseApps.includes(app) baseApps.includes(app)
) )
} else { } else {
// Just category filter // Just category filter
apps = AppSearchService.getAppsInCategory(selectedCategory) if (selectedCategory === "Recents") {
// For recents, use the recent apps from Prefs
apps = recentApps.map(recentApp => AppSearchService.getAppByExec(recentApp.exec)).filter(app => app !== null)
} else {
apps = AppSearchService.getAppsInCategory(selectedCategory)
}
} }
// Add to model // Add to model
@@ -406,69 +415,6 @@ PanelWindow {
} }
} }
// Recent apps section
Column {
width: parent.width
spacing: Theme.spacingS
visible: recentApps.length > 0 && searchField.text.length === 0
Text {
text: "Recently Used"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
}
Row {
width: parent.width
spacing: Theme.spacingM
Repeater {
model: Math.min(recentApps.length, 5)
Rectangle {
width: 56
height: 56
radius: Theme.cornerRadius
color: recentAppMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
border.width: 1
IconImage {
anchors.fill: parent
anchors.margins: 8
source: recentApps[index] ? Quickshell.iconPath(recentApps[index].icon, "") : ""
smooth: true
asynchronous: true
}
MouseArea {
id: recentAppMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (recentApps[index]) {
var recentApp = recentApps[index]
// Find the desktop entry for this recent app
var foundApp = AppSearchService.getAppByExec(recentApp.exec)
if (foundApp) {
Prefs.addRecentApp(foundApp)
AppSearchService.launchApp(foundApp)
} else {
// Fallback to direct execution
var cleanExec = recentApp.exec.replace(/%[fFuU]/g, "").trim()
Quickshell.execDetached(["sh", "-c", cleanExec])
}
launcher.hide()
}
}
}
}
}
}
}
// Category filter and view mode controls // Category filter and view mode controls
Row { Row {
width: parent.width width: parent.width
@@ -592,7 +538,6 @@ PanelWindow {
// Calculate more precise remaining height // Calculate more precise remaining height
let usedHeight = 40 + Theme.spacingL // Header let usedHeight = 40 + Theme.spacingL // Header
usedHeight += 52 + Theme.spacingL // Search container usedHeight += 52 + Theme.spacingL // Search container
usedHeight += (recentApps.length > 0 && searchField.text.length === 0 ? 56 + Theme.spacingS + Theme.spacingL : 0) // Recent apps when visible
usedHeight += (searchField.text.length === 0 ? 40 + Theme.spacingL : 0) // Category/controls when visible usedHeight += (searchField.text.length === 0 ? 40 + Theme.spacingL : 0) // Category/controls when visible
return parent.height - usedHeight return parent.height - usedHeight
} }
@@ -966,7 +911,9 @@ PanelWindow {
Component.onCompleted: { Component.onCompleted: {
if (AppSearchService.ready) { if (AppSearchService.ready) {
categories = AppSearchService.getAllCategories() var allCategories = AppSearchService.getAllCategories()
// Insert "Recents" after "All"
categories = ["All", "Recents"].concat(allCategories.filter(cat => cat !== "All"))
updateFilteredModel() updateFilteredModel()
} }
recentApps = Prefs.getRecentApps() // Load recent apps on startup recentApps = Prefs.getRecentApps() // Load recent apps on startup

View File

@@ -12,11 +12,15 @@ PanelWindow {
id: spotlightLauncher id: spotlightLauncher
property bool spotlightOpen: false property bool spotlightOpen: false
property var recentApps: []
property var filteredApps: [] property var filteredApps: []
property int selectedIndex: 0 property int selectedIndex: 0
property int maxResults: 50 property int maxResults: 50
property var categories: AppSearchService.getAllCategories().filter(cat => cat !== "Education" && cat !== "Science") property var categories: {
var allCategories = AppSearchService.getAllCategories().filter(cat => cat !== "Education" && cat !== "Science")
// Insert "Recents" after "All"
var result = ["All", "Recents"]
return result.concat(allCategories.filter(cat => cat !== "All"))
}
property string selectedCategory: "All" property string selectedCategory: "All"
property string viewMode: "list" // "list" or "grid" property string viewMode: "list" // "list" or "grid"
@@ -45,7 +49,6 @@ PanelWindow {
console.log("SpotlightLauncher: show() called") console.log("SpotlightLauncher: show() called")
spotlightOpen = true spotlightOpen = true
console.log("SpotlightLauncher: spotlightOpen set to", spotlightOpen) console.log("SpotlightLauncher: spotlightOpen set to", spotlightOpen)
loadRecentApps()
updateFilteredApps() updateFilteredApps()
Qt.callLater(function() { Qt.callLater(function() {
searchField.forceActiveFocus() searchField.forceActiveFocus()
@@ -69,9 +72,6 @@ PanelWindow {
} }
} }
function loadRecentApps() {
recentApps = Prefs.getRecentApps()
}
function updateFilteredApps() { function updateFilteredApps() {
filteredApps = [] filteredApps = []
@@ -80,53 +80,34 @@ PanelWindow {
var apps = [] var apps = []
if (searchField.text.length === 0) { if (searchField.text.length === 0) {
// Show recent apps first, then all apps from category // Show apps from category
if (selectedCategory === "All") { if (selectedCategory === "All") {
// For "All" category, show recent apps first, then all available apps // For "All" category, show all available apps
var allApps = AppSearchService.applications || [] apps = AppSearchService.applications || []
var combined = [] } else if (selectedCategory === "Recents") {
// For "Recents" category, get recent apps from Prefs
// Add recent apps first var recentApps = Prefs.getRecentApps()
recentApps.forEach(recentApp => { apps = recentApps.map(recentApp => AppSearchService.getAppByExec(recentApp.exec)).filter(app => app !== null)
var found = allApps.find(app => app.exec === recentApp.exec)
if (found) {
combined.push(found)
}
})
// Add remaining apps not in recent
var remaining = allApps.filter(app => {
return !recentApps.some(recentApp => recentApp.exec === app.exec)
})
combined = combined.concat(remaining)
apps = combined // Show all apps for "All" category
} else { } else {
// For specific categories, limit results // For specific categories, limit results
var categoryApps = AppSearchService.getAppsInCategory(selectedCategory) var categoryApps = AppSearchService.getAppsInCategory(selectedCategory)
var combined = [] apps = categoryApps.slice(0, maxResults)
// Add recent apps first if they match category
recentApps.forEach(recentApp => {
var found = categoryApps.find(app => app.exec === recentApp.exec)
if (found) {
combined.push(found)
}
})
// Add remaining apps not in recent
var remaining = categoryApps.filter(app => {
return !recentApps.some(recentApp => recentApp.exec === app.exec)
})
combined = combined.concat(remaining)
apps = combined.slice(0, maxResults)
} }
} else { } else {
// Search with category filter // Search with category filter
if (selectedCategory === "All") { if (selectedCategory === "All") {
// For "All" category, search all apps without limit // For "All" category, search all apps without limit
apps = AppSearchService.searchApplications(searchField.text) apps = AppSearchService.searchApplications(searchField.text)
} else if (selectedCategory === "Recents") {
// For "Recents" category, search within recent apps
var recentApps = Prefs.getRecentApps()
var recentDesktopEntries = recentApps.map(recentApp => AppSearchService.getAppByExec(recentApp.exec)).filter(app => app !== null)
var allSearchResults = AppSearchService.searchApplications(searchField.text)
// Filter search results to only include recent apps
apps = allSearchResults.filter(searchApp => {
return recentDesktopEntries.some(recentApp => recentApp.name === searchApp.name)
})
} else { } else {
// For specific categories, filter search results by category // For specific categories, filter search results by category
var categoryApps = AppSearchService.getAppsInCategory(selectedCategory) var categoryApps = AppSearchService.getAppsInCategory(selectedCategory)
@@ -215,18 +196,15 @@ PanelWindow {
target: AppSearchService target: AppSearchService
function onReadyChanged() { function onReadyChanged() {
if (AppSearchService.ready) { if (AppSearchService.ready) {
categories = AppSearchService.getAllCategories().filter(cat => cat !== "Education" && cat !== "Science") var allCategories = AppSearchService.getAllCategories().filter(cat => cat !== "Education" && cat !== "Science")
// Insert "Recents" after "All"
var result = ["All", "Recents"]
categories = result.concat(allCategories.filter(cat => cat !== "All"))
if (spotlightOpen) updateFilteredApps() if (spotlightOpen) updateFilteredApps()
} }
} }
} }
Connections {
target: Prefs
function onRecentlyUsedAppsChanged() {
recentApps = Prefs.getRecentApps()
}
}
// Dimmed overlay background // Dimmed overlay background
Rectangle { Rectangle {
@@ -242,29 +220,23 @@ PanelWindow {
id: mainContainer id: mainContainer
width: 600 width: 600
height: { height: {
// Calculate dynamic height based on content // Fixed height to prevent shrinking - consistent experience
let baseHeight = Theme.spacingXL * 2 + Theme.spacingL * 4 // Margins and spacing let baseHeight = Theme.spacingXL * 2 + Theme.spacingL * 3 // Margins and spacing
// Add category section height if visible // Add category section height if visible
if (categories.length > 1 || filteredModel.count > 0) { if (categories.length > 1 || filteredModel.count > 0) {
baseHeight += 36 * 2 + Theme.spacingS + Theme.spacingM // Categories (2 rows) baseHeight += 36 * 2 + Theme.spacingS + Theme.spacingM // Categories (2 rows)
} }
// Add recent apps section height if visible
if (recentApps.length > 0 && searchField.text.length === 0) {
baseHeight += 56 + Theme.spacingS + Theme.fontSizeMedium + Theme.spacingL // Recent apps
}
// Add search field height // Add search field height
baseHeight += 56 baseHeight += 56
// Add results height (limit to reasonable size) // Add fixed results height for consistent size
let maxResultsHeight = 400 let fixedResultsHeight = 400 // Always same height regardless of content
let actualResultsHeight = Math.min(filteredModel.count * (viewMode === "grid" ? 100 : 60), maxResultsHeight) baseHeight += fixedResultsHeight
baseHeight += actualResultsHeight
// Ensure minimum and maximum bounds // Ensure reasonable bounds
return Math.min(Math.max(baseHeight, 300), parent.height - 40) return Math.min(Math.max(baseHeight, 500), parent.height - 40)
} }
anchors.centerIn: parent anchors.centerIn: parent
color: Theme.surfaceContainer color: Theme.surfaceContainer
@@ -306,7 +278,7 @@ PanelWindow {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
property var topRowCategories: ["All", "Development", "Graphics", "Internet"] property var topRowCategories: ["All", "Recents", "Development", "Graphics"]
Repeater { Repeater {
model: parent.topRowCategories.filter(cat => categories.includes(cat)) model: parent.topRowCategories.filter(cat => categories.includes(cat))
@@ -320,7 +292,7 @@ PanelWindow {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: modelData text: modelData
color: selectedCategory === modelData ? Theme.onPrimary : Theme.surfaceText color: selectedCategory === modelData ? Theme.surface : Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
font.weight: selectedCategory === modelData ? Font.Medium : Font.Normal font.weight: selectedCategory === modelData ? Font.Medium : Font.Normal
elide: Text.ElideRight elide: Text.ElideRight
@@ -344,7 +316,7 @@ PanelWindow {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
property var bottomRowCategories: ["Media", "Office", "Settings", "System", "Utilities"] property var bottomRowCategories: ["Internet", "Media", "Office", "Settings", "System"]
Repeater { Repeater {
model: parent.bottomRowCategories.filter(cat => categories.includes(cat)) model: parent.bottomRowCategories.filter(cat => categories.includes(cat))
@@ -358,7 +330,7 @@ PanelWindow {
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: modelData text: modelData
color: selectedCategory === modelData ? Theme.onPrimary : Theme.surfaceText color: selectedCategory === modelData ? Theme.surface : Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
font.weight: selectedCategory === modelData ? Font.Medium : Font.Normal font.weight: selectedCategory === modelData ? Font.Medium : Font.Normal
elide: Text.ElideRight elide: Text.ElideRight
@@ -379,73 +351,6 @@ PanelWindow {
} }
} }
// Recent apps section
Column {
width: parent.width
spacing: Theme.spacingS
visible: recentApps.length > 0 && searchField.text.length === 0
Text {
text: "Recently Used"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM
Repeater {
model: Math.min(recentApps.length, 5)
Rectangle {
width: 56
height: 56
radius: Theme.cornerRadius
color: recentSpotlightMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
border.width: 1
IconImage {
anchors.fill: parent
anchors.margins: 8
source: recentApps[index] ? Quickshell.iconPath(recentApps[index].icon, "") : ""
smooth: true
asynchronous: true
}
MouseArea {
id: recentSpotlightMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (recentApps[index]) {
var recentApp = recentApps[index]
// Find the desktop entry for this recent app
var foundApp = AppSearchService.getAppByExec(recentApp.exec)
if (foundApp) {
launchApp({
name: foundApp.name,
exec: foundApp.execString,
icon: foundApp.icon,
comment: foundApp.comment,
desktopEntry: foundApp
})
} else {
// Fallback to direct execution
launchApp(recentApp)
}
}
}
}
}
}
}
}
// Search field with view toggle buttons // Search field with view toggle buttons
Row { Row {
width: parent.width width: parent.width
@@ -497,7 +402,7 @@ PanelWindow {
Text { Text {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: recentApps.length > 0 ? "Search applications or select from recent..." : "Search applications..." text: "Search applications..."
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
visible: searchField.text.length === 0 && !searchField.activeFocus visible: searchField.text.length === 0 && !searchField.activeFocus
@@ -807,8 +712,10 @@ PanelWindow {
Component.onCompleted: { Component.onCompleted: {
console.log("SpotlightLauncher: Component.onCompleted called - component loaded successfully!") console.log("SpotlightLauncher: Component.onCompleted called - component loaded successfully!")
if (AppSearchService.ready) { if (AppSearchService.ready) {
categories = AppSearchService.getAllCategories().filter(cat => cat !== "Education" && cat !== "Science") var allCategories = AppSearchService.getAllCategories().filter(cat => cat !== "Education" && cat !== "Science")
// Insert "Recents" after "All"
var result = ["All", "Recents"]
categories = result.concat(allCategories.filter(cat => cat !== "All"))
} }
loadRecentApps() // Load recent apps on startup
} }
} }