Add application and autostart settings
This commit is contained in:
@@ -1,19 +1,207 @@
|
||||
// Applications — PLACEHOLDER.
|
||||
//
|
||||
// Owned by the codex agent, which is building default-application handling and
|
||||
// the autostart list. This stub exists only so the page id can be routed,
|
||||
// registered, and searchable before that work lands; it is expected to be
|
||||
// replaced wholesale rather than edited.
|
||||
// Applications and session startup.
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.services
|
||||
|
||||
SettingsPage {
|
||||
id: root
|
||||
|
||||
objectName: "applications"
|
||||
title: "Applications"
|
||||
lede: "Default applications and what starts with your session."
|
||||
lede: "Choose what opens your files and links, and what starts with your session."
|
||||
|
||||
property string expandedRole: ""
|
||||
readonly property var applications: DesktopEntries.applications.values
|
||||
readonly property var roles: [
|
||||
{ key: "browser", label: "Browser", detail: "Web links and HTML pages", categories: ["webbrowser"], terms: ["browser", "web"] },
|
||||
{ key: "mail", label: "Mail", detail: "Email links", categories: ["email"], terms: ["mail", "email"] },
|
||||
{ key: "files", label: "Files", detail: "Folders and file locations", categories: ["filemanager"], terms: ["file manager", "files"] },
|
||||
{ key: "terminal", label: "Terminal", detail: "Terminal links and command-line handoffs", categories: ["terminalemulator"], terms: ["terminal", "console"] },
|
||||
{ key: "music", label: "Music", detail: "MP3 audio", categories: ["audio", "player"], terms: ["music", "audio player"] },
|
||||
{ key: "images", label: "Images", detail: "PNG images", categories: ["graphics", "viewer"], terms: ["image", "photo", "picture"] },
|
||||
{ key: "video", label: "Video", detail: "MP4 video", categories: ["video", "player"], terms: ["video", "media player"] }
|
||||
]
|
||||
|
||||
function desktopId(entry: var): string {
|
||||
const entryId = String(entry?.id ?? "");
|
||||
return entryId.endsWith(".desktop") ? entryId : entryId + ".desktop";
|
||||
}
|
||||
|
||||
function displayName(entry: var): string {
|
||||
return String(entry?.name || entry?.genericName || root.desktopId(entry));
|
||||
}
|
||||
|
||||
function currentHandler(role: string): string {
|
||||
return String(DefaultApps.handlers[role] ?? "");
|
||||
}
|
||||
|
||||
function currentEntry(role: string): var {
|
||||
const handler = root.currentHandler(role);
|
||||
return root.applications.find(entry => root.desktopId(entry) === handler) ?? null;
|
||||
}
|
||||
|
||||
function matchesRole(entry: var, role: var): bool {
|
||||
const categories = Array.isArray(entry.categories)
|
||||
? entry.categories.join(" ").toLowerCase()
|
||||
: String(entry.categories ?? "").toLowerCase();
|
||||
const metadata = [entry.name, entry.genericName, entry.comment]
|
||||
.map(value => String(value ?? "").toLowerCase())
|
||||
.join(" ");
|
||||
return role.categories.some(category => categories.includes(category))
|
||||
|| role.terms.some(term => metadata.includes(term));
|
||||
}
|
||||
|
||||
function choicesForRole(role: var): var {
|
||||
const choices = root.applications.filter(entry => root.matchesRole(entry, role));
|
||||
const currentEntry = root.currentEntry(role.key);
|
||||
if (currentEntry && !choices.some(entry => root.desktopId(entry) === root.desktopId(currentEntry)))
|
||||
choices.push(currentEntry);
|
||||
return choices.sort((left, right) => root.displayName(left).localeCompare(root.displayName(right)));
|
||||
}
|
||||
|
||||
TextRow {
|
||||
visible: DefaultApps.lastError !== ""
|
||||
label: "Could not apply the change"
|
||||
detail: DefaultApps.lastError
|
||||
value: ""
|
||||
divider: false
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Being built"
|
||||
subtitle: "Default browser, mail, files, and terminal, plus the autostart list, are on their way."
|
||||
title: "Default applications"
|
||||
subtitle: "Open a row to choose from applications that advertise the matching role."
|
||||
|
||||
Repeater {
|
||||
model: root.roles
|
||||
|
||||
delegate: Column {
|
||||
id: roleBlock
|
||||
|
||||
required property var modelData
|
||||
required property int index
|
||||
readonly property var choices: root.choicesForRole(roleBlock.modelData)
|
||||
readonly property var selectedEntry: root.currentEntry(roleBlock.modelData.key)
|
||||
|
||||
width: parent.width
|
||||
|
||||
SettingRow {
|
||||
label: roleBlock.modelData.label
|
||||
detail: roleBlock.modelData.detail
|
||||
value: roleBlock.selectedEntry
|
||||
? root.displayName(roleBlock.selectedEntry)
|
||||
: (root.currentHandler(roleBlock.modelData.key) || "Not set")
|
||||
activatable: roleBlock.choices.length > 0 && !DefaultApps.busy
|
||||
divider: root.expandedRole !== roleBlock.modelData.key && roleBlock.index < root.roles.length - 1
|
||||
onActivated: {
|
||||
root.expandedRole = root.expandedRole === roleBlock.modelData.key
|
||||
? ""
|
||||
: roleBlock.modelData.key;
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
visible: root.expandedRole === roleBlock.modelData.key
|
||||
|
||||
Repeater {
|
||||
model: roleBlock.choices
|
||||
|
||||
delegate: SettingRow {
|
||||
id: candidateRow
|
||||
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
readonly property string candidateId: root.desktopId(candidateRow.modelData)
|
||||
readonly property bool selected: candidateRow.candidateId === root.currentHandler(roleBlock.modelData.key)
|
||||
|
||||
label: root.displayName(candidateRow.modelData)
|
||||
detail: String(candidateRow.modelData.genericName || candidateRow.modelData.comment || candidateRow.candidateId)
|
||||
value: candidateRow.selected ? "Current" : ""
|
||||
activatable: !candidateRow.selected && !DefaultApps.busy
|
||||
divider: candidateRow.index < roleBlock.choices.length - 1 || roleBlock.index < root.roles.length - 1
|
||||
onActivated: {
|
||||
DefaultApps.setDefault(roleBlock.modelData.key, candidateRow.candidateId);
|
||||
root.expandedRole = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "User autostart"
|
||||
subtitle: "These desktop entries live in your user configuration. Select a row to toggle it."
|
||||
|
||||
TextRow {
|
||||
visible: DefaultApps.autostartEntries.length === 0
|
||||
label: "No user autostart entries"
|
||||
detail: "Applications can add entries to ~/.config/autostart."
|
||||
value: ""
|
||||
divider: false
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: DefaultApps.autostartEntries
|
||||
|
||||
delegate: SettingRow {
|
||||
id: autostartRow
|
||||
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
label: autostartRow.modelData.name
|
||||
detail: autostartRow.modelData.id
|
||||
value: autostartRow.modelData.enabled ? "Enabled" : "Disabled"
|
||||
activatable: !DefaultApps.busy
|
||||
divider: autostartRow.index < DefaultApps.autostartEntries.length - 1
|
||||
onActivated: DefaultApps.setAutostart(autostartRow.modelData.id, !autostartRow.modelData.enabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Compositor autostart"
|
||||
subtitle: "Panama starts these from Hyprland configuration. They are read-only here."
|
||||
|
||||
TextRow {
|
||||
visible: DefaultApps.luaAutostartEntries.length === 0
|
||||
label: "No compositor entries found"
|
||||
detail: "No hl.exec_cmd entries were found in config/dot/hypr/autostart.lua."
|
||||
value: ""
|
||||
divider: false
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: DefaultApps.luaAutostartEntries
|
||||
|
||||
delegate: TextRow {
|
||||
id: luaRow
|
||||
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
label: luaRow.modelData.name
|
||||
detail: luaRow.modelData.command
|
||||
value: "Hyprland"
|
||||
divider: luaRow.index < DefaultApps.luaAutostartEntries.length - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Refresh"
|
||||
|
||||
ActionRow {
|
||||
label: "Reload application settings"
|
||||
detail: "Re-read desktop entries, defaults, and user autostart files"
|
||||
action: DefaultApps.busy ? "Refreshing…" : "Refresh"
|
||||
enabled: !DefaultApps.busy
|
||||
divider: false
|
||||
onTriggered: DefaultApps.refresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user