Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions desktop-launcher/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Desktop Launcher

Desktop widget to launch your favorite apps from your desktop in one click.

## Plugin

| Field | Value |
| --- | --- |
| ID | `yocraft/desktop-launcher` |
| Entries | Desktop widget: `widget` |

## Usage

Add it to your desktop/lockscreen widgets using the widget editor. You can configure it in the widget settings.

## Settings

| Setting | Type | Default | Description |
| --- | --- | --- | --- |
| `apps` | `string_list` | `` | Apps list and order. |
| `layout` | `bool` | `false` | Display applications in a grid layout. |
| `columns` | `int` | `5` | Number of columns for the grid layout. |

## Notes

Flatpak is supported.
40 changes: 40 additions & 0 deletions desktop-launcher/plugin.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
id = "yocraft/desktop-launcher"
name = "Desktop Launcher"
version = "1.0.0"
plugin_api = 3
author = "yocraft"
license = "MIT"
deprecated = false
icon = "launcher"
description = "Launch your favorite apps from your desktop in one click."
tags = [ "desktop", "utility" ]
dependencies = []

[[desktop_widget]]
id = "widget"
entry = "widget.luau"

[[desktop_widget.setting]]
key = "apps"
type = "string_list"
label_key = "settings.apps.label"
default = [
"firefox",
"foot",
"nvim",
]

[[desktop_widget.setting]]
key = "grid_layout"
type = "bool"
label_key = "settings.grid_layout.label"
default = false

[[desktop_widget.setting]]
key = "columns"
type = "int"
label_key = "settings.columns.label"
default = 5
min = 1
max = 20
visible_when = { key = "grid_layout", values = ["true"] }
Binary file added desktop-launcher/thumbnail.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions desktop-launcher/translations/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"settings": {
"apps": {
"label": "Applications"
},
"grid_layout": {
"label": "Grid Layout"
},
"columns": {
"label": "Columns"
}
}
}
168 changes: 168 additions & 0 deletions desktop-launcher/widget.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
local function getConf(key, default)
local value = noctalia.getConfig(key)
if value == nil then
return default
else
return value
end
end

local config = {
grid_layout = getConf("grid_layout", false),
columns = getConf("columns", 5),
}

-- https://github.com/noctalia-dev/noctalia/blob/main/src/system/desktop_entry_launch.cpp#L45
local function stripFieldCodes(exec)
local result = exec:gsub("%%(.?)( ?)", function(nextChar, trailingSpace)
if nextChar:match("[fFuUdDnNick]") then
return ""
elseif nextChar == "%" then
return "%" .. trailingSpace
else
return "%" .. nextChar .. trailingSpace
end
end)

result = result:gsub(" +$", "")

-- Flatpak
result = result:gsub("@@u *@@", "")

return result
end

local function getContent(appid)
local paths = {
"~/.local/share/applications/",
"~/.local/share/flatpak/exports/share/applications/",
"/usr/local/share/applications/",
"/usr/share/applications/",
"/var/lib/flatpak/exports/share/applications/",
}

for _, path in ipairs(paths) do
local content = noctalia.readFile(path .. appid .. ".desktop")
if content then
return content
end
end

return nil
end

local function getKeyContent(content, key)
return content:match("[\r\n]" .. key .. "=([^\r\n]*)")
end

local function parse(appid)
local content = getContent(appid)
if not content then
return nil
end

local data = {}

local name = getKeyContent(content, "Name")
if name then
data.name = name
end

local exec = getKeyContent(content, "Exec")
if exec then
data.exec = stripFieldCodes(exec)
end

local terminal = getKeyContent(content, "Terminal")
if terminal then
data.terminal = terminal == "true"
end

return data
end

local function appBox(app, data)
return ui.column({
fill = "surface",
padding = 8,
radius = 12,
align = "center",
minWidth = 100,
justify = "space_between",
gap = 4,
onClick = function() launchApp(data.exec, data.terminal) end
}, {
ui.image({
path = noctalia.appIconPath(app),
width = 60,
height = 60,
}),
ui.label({
text = data.name,
fontWeight = "heavy",
maxWidth = 84,
maxLines = 1,
fontSize = 14,
})
})
end

local function getApps()
local apps = noctalia.getConfig("apps")
local appsTable = {}

for _, app in ipairs(apps) do
local data = parse(app)
if not data then
noctalia.log("desktop-launcher: invalid desktop entry, skipping " .. app)
continue
end

table.insert(appsTable, appBox(app, data))
end

return appsTable
end

local function getRows(apps)
local rows = {}
local row = {}

for i, app in ipairs(apps) do
table.insert(row, app)

if #row == config.columns or i == #apps then
table.insert(rows,
ui.row({ gap = 8 }, row)
)

row = {}
end
end

return rows
end

local function render()
local apps = getApps()

if config.grid_layout then
desktopWidget.render(ui.column({ gap = 8, },
getRows(apps)
))
else
desktopWidget.render(ui.row({ gap = 8, },
apps
))
end
end

function launchApp(exec, terminal)
if terminal then
noctalia.runInTerminal(exec)
else
noctalia.runAsync(exec)
end
end

render()
Loading