diff --git a/battery-widget/README.md b/battery-widget/README.md new file mode 100644 index 0000000..6212b91 --- /dev/null +++ b/battery-widget/README.md @@ -0,0 +1,34 @@ +# Battery Widget + +Desktop/lockscreen widget that displays the current battery level and charging status. + +## Plugin + +| Field | Value | +| --- | --- | +| ID | `yocraft/battery-widget` | +| Entries | Desktop widget: `widget` | + +## Usage + +Add it to your desktop/lockscreen widgets. + +## Settings + +| Setting | Type | Default | Description | +| --- | --- | --- | --- | +| `layout` | `select` | `horizontal` | Layout of the widget. | +| `show_glyph` | `bool` | `true` | Show the battery icon. | +| `show_label` | `bool` | `true` | Show text next to the icon. | +| `hide_plugged` | `bool` | `false` | Hide the battery widget when connected to AC power. | +| `hide_full` | `bool` | `false` | Hide the battery widget when fully charged. | +| `color` | `color` | `on_surface` | Color role for this widget's icon and label; fixed hex colors are also supported. | +| `warning_color` | `color` | `error` | Color applied when charge is at or below 20%. | +| `charging_color` | `color` | `on_surface` | Color applied when connected to AC power. | +| `battery` | `select` | `auto` | Detect the battery automatically or set a custom name. | +| `battery_name` | `string` | `BAT0` | Set a custom name for the battery. | +| `refresh_interval` | `int` | `60` | Controls how frequently the widget updates its content. (in seconds) | + +## Notes + +`hide_full` and `hide_plugged` do not hide the background due to plugin limitations. diff --git a/battery-widget/plugin.toml b/battery-widget/plugin.toml new file mode 100644 index 0000000..2cd49e0 --- /dev/null +++ b/battery-widget/plugin.toml @@ -0,0 +1,109 @@ +id = "yocraft/battery-widget" +name = "Battery Widget" +version = "1.0.0" +plugin_api = 19 +author = "yocraft" +license = "MIT" +deprecated = false +icon = "battery" +description = "Desktop/Lockscreen widget to show battery." +tags = [ "desktop", "hardware", "system", "utility" ] +dependencies = [] + +[[desktop_widget]] +id = "widget" +entry = "widget.luau" + +[[setting]] +key = "layout" +type = "select" +label_key = "settings.layout.label" +description_key = "settings.layout.description" +default = "horizontal" +options = [ + { value = "horizontal", label_key = "settings.layout.horizontal" }, + { value = "vertical", label_key = "settings.layout.vertical" }, +] + +[[setting]] +key = "show_glyph" +type = "bool" +label_key = "settings.show_glyph.label" +description_key = "settings.show_glyph.description" +default = true + +[[setting]] +key = "show_label" +type = "bool" +label_key = "settings.show_label.label" +description_key = "settings.show_label.description" +default = true + +[[setting]] +key = "hide_plugged" +type = "bool" +label_key = "settings.hide_plugged.label" +description_key = "settings.hide_plugged.description" +default = false + +[[setting]] +key = "hide_full" +type = "bool" +label_key = "settings.hide_full.label" +description_key = "settings.hide_full.description" +default = false + + +[[setting]] +key = "color" +type = "color" +label_key = "settings.color.label" +description_key = "settings.color.description" +default = "on_surface" +advanced = true + +[[setting]] +key = "warning_color" +type = "color" +label_key = "settings.warning_color.label" +description_key = "settings.warning_color.description" +default = "error" +advanced = true + +[[setting]] +key = "charging_color" +type = "color" +label_key = "settings.charging_color.label" +description_key = "settings.charging_color.description" +default = "on_surface" +advanced = true + + +[[setting]] +key = "battery" +type = "select" +label_key = "settings.battery.label" +description_key = "settings.battery.description" +default = "auto" +options = [ + { value = "auto", label_key = "settings.battery.auto" }, + { value = "bat0", label_key = "settings.battery.bat0" }, + { value = "custom", label_key = "settings.battery.custom" }, +] + +[[setting]] +key = "battery_name" +type = "string" +label_key = "settings.battery_name.label" +description_key = "settings.battery_name.description" +default = "BAT0" +visible_when = { key = "battery", values = ["custom"] } + +[[setting]] +key = "refresh_interval" +type = "int" +label_key = "settings.refresh_interval.label" +description_key = "settings.refresh_interval.description" +default = 60 +min = 1 +max = 600 diff --git a/battery-widget/thumbnail.webp b/battery-widget/thumbnail.webp new file mode 100644 index 0000000..5a409fc Binary files /dev/null and b/battery-widget/thumbnail.webp differ diff --git a/battery-widget/translations/en.json b/battery-widget/translations/en.json new file mode 100644 index 0000000..8ac815e --- /dev/null +++ b/battery-widget/translations/en.json @@ -0,0 +1,53 @@ +{ + "settings": { + "layout": { + "label": "Layout", + "description": "Widget layout.", + "horizontal": "Horizontal", + "vertical": "Vertical" + }, + "show_label": { + "label": "Show Label", + "description": "Show text next to the icon." + }, + "show_glyph": { + "label": "Show Glyph", + "description": "Show the battery icon." + }, + "hide_plugged": { + "label": "Hide When Plugged In", + "description": "Hide the battery widget when connected to AC power." + }, + "hide_full": { + "label": "Hide When Full", + "description": "Hide the battery widget when fully charged." + }, + "color": { + "label": "Color", + "description": "Color role for this widget's icon and label; fixed hex colors are also supported." + }, + "warning_color": { + "label": "Warning Color", + "description": "Color applied when charge is at or below 20%." + }, + "charging_color": { + "label": "Charging Color", + "description": "Color applied when connected to AC power." + }, + "battery": { + "label": "Battery", + "description": "Detect the battery automatically or set a custom name.", + "auto": "Auto", + "bat0": "BAT0", + "custom": "Custom" + }, + "battery_name": { + "label": "Battery Name", + "description": "Name of the battery." + }, + "refresh_interval": { + "label": "Refresh Interval", + "description": "Controls how frequently the widget updates its content. (in seconds)" + } + } +} diff --git a/battery-widget/widget.luau b/battery-widget/widget.luau new file mode 100644 index 0000000..76a0560 --- /dev/null +++ b/battery-widget/widget.luau @@ -0,0 +1,119 @@ +noctalia.setUpdateInterval(noctalia.getConfig("refresh_interval") * 1000) + +local glyph +local color +local percent +local status + +local path = "/sys/class/power_supply/" +local batName + +local function getBatName() + local config = noctalia.getConfig("battery") + + if config == "bat0" then + return "BAT0" + elseif config == "custom" then + return noctalia.getConfig("battery_name") + end + + local folders = noctalia.listDir(path) + + if folders then + for _, name in ipairs(folders) do + if name:match("^BAT") then + return name + end + end + end + return nil +end + +local function getGlyph() + if status == "Charging" then + glyph = "battery-charging" + elseif status == "Full" or status == "Not Charging" then + glyph = "battery-plugged" + elseif status == "Unknown" then + glyph = "battery-exclamation" + else + glyph = percent >= 85 and "battery-4" + or percent >= 55 and "battery-3" + or percent >= 30 and "battery-2" + or percent >= 10 and "battery-1" + or "battery-0" + end +end + +local function getColor() + if status ~= "Charging" and percent <= 20 then + color = noctalia.getConfig("warning_color") + return + end + if status == "Charging" or status == "Full" or status == "Not Charging" then + color = noctalia.getConfig("charging_color") + return + end + color = noctalia.getConfig("color") +end + +local function render() + if (noctalia.getConfig("hide_plugged") and (status == "Charging" or status == "Not Charging")) + or (noctalia.getConfig("hide_full") and status == "Full") then + desktopWidget.render(ui.row()) + return + end + + local content = {} + if noctalia.getConfig("show_glyph") then + table.insert(content, ui.glyph({ name = glyph, color = color })) + end + if noctalia.getConfig("show_label") then + table.insert(content, ui.label({ text = percent .. "%", color = color })) + end + + local layout = noctalia.getConfig("layout") == "vertical" and ui.column or ui.row + + desktopWidget.render(layout({ gap = 4, align = "center" }, content)) +end + +local function refreshBattery() + noctalia.runAsync( + "cat " + .. path .. batName .. "/capacity " + .. path .. batName .. "/status", + function(result) + if result.exitCode ~= 0 then + noctalia.log("battery-widget: failed to read battery: " .. result.stderr) + return + end + + local lines = {} + for line in result.stdout:gmatch("[^\r\n]+") do + table.insert(lines, line) + end + + if not lines[1] or not lines[2] then + noctalia.log("battery-widget: invalid battery output") + return + end + + percent = tonumber(noctalia.string.trim(lines[1])) + status = noctalia.string.trim(lines[2]) + + getGlyph() + getColor() + render() + end + ) +end + +batName = getBatName() +if not batName then + noctalia.log("battery-widget: battery not found") + return +end + +function update() + refreshBattery() +end