Files
community-plugins/ip-monitor/desktop.luau
T
3ri4nG0ldandGitHub fb5dd0506e feat: add ip-monitor plugin (#207)
* Add ip-monitor plugin

* fix: removed typo

* feat: increase default refresh interval to 60 seconds

* fix: prevent shell injection in IP monitor gateway lookup.

* docs: fix author casing in README

* feat: add configurable click actions

* feat: add desktop widget support and refactor core logic

- Extracted IP fetching and data parsing into a shared `utils.luau` module to prevent code duplication.
- Created `desktop.luau` to display network details explicitly in a tabulated UI.
- Added specific configuration options for font sizes and colors for the new desktop widget

* feat: add hidden_fields configuration to allow filtering tooltip and desktop widget details

* fix: remove raw HTML from README

* refactor(utils): use bit32 and fix glob pattern escaping & gateway parsing

* refactor(utils): centralize shared UI builder and display name resolution

* refactor(widget): use shared utils helpers and clean up duplicate logic

* refactor(desktop): use shared utils helpers and add IPC click action parity

* docs: update README with desktop widget settings

* feat: remove unused IPC copy actions from widget logic
2026-08-02 22:25:35 -04:00

158 lines
5.6 KiB
Luau

-------------------------------------------------------------------------------
-- IP Monitor Desktop Widget for Noctalia
--
-- Monitors network IP addresses and displays details on the desktop.
-------------------------------------------------------------------------------
local utils = require("./utils.luau")
-- Current runtime state
local currentIp = ""
local currentIpcName = ""
local currentTooltip = nil
-------------------------------------------------------------------------------
-- HELPER FUNCTIONS
-------------------------------------------------------------------------------
--- Resolves the active display name according to active mode and IPC state.
local function getDisplayName()
return utils.getDisplayName(noctalia.getConfig("mode"), currentIpcName, noctalia.getConfig("name"))
end
local function copyNotifyAndLog(text, optionKey, logMessage)
if text and text ~= "" then
noctalia.copyToClipboard(text, "text/plain")
noctalia.notify(noctalia.tr("name"), noctalia.tr(optionKey) .. ": " .. text)
noctalia.log("ip-monitor: " .. logMessage .. ": " .. text)
end
end
local function applyAction(action)
if action == "copy_ip" then
copyNotifyAndLog(currentIp, "settings.click.options.copy_ip", "copied IP to clipboard")
elseif action == "copy_name" then
copyNotifyAndLog(getDisplayName(), "settings.click.options.copy_name", "copied name to clipboard")
end
end
-------------------------------------------------------------------------------
-- UI RENDERING
-------------------------------------------------------------------------------
--- Renders the desktop widget UI based on current state and user settings.
local function render()
local hideOnEmpty = noctalia.getConfig("hide_on_empty")
if hideOnEmpty == nil then hideOnEmpty = true end
-- Omit rendering completely if no IP is present and hide_on_empty is active
if hideOnEmpty and (not currentIp or currentIp == "") then
desktopWidget.render(ui.row({}, {}))
return
end
local ipFontSize = noctalia.getConfig("ip_font_size") or 32
local detailsFontSize = noctalia.getConfig("details_font_size") or 16
local displayName = getDisplayName()
local topRowContent = utils.buildTopRow(currentIp, displayName, ipFontSize)
local content = {}
table.insert(content, ui.row({ gap = 8, align = "center", justify = "center" }, topRowContent))
-- Add Details
if currentTooltip then
local hiddenConfig = noctalia.getConfig("hidden_fields")
local hiddenFields = utils.parseHiddenFields(hiddenConfig)
local colKeys = {}
local colValues = {}
local fields = { "iface", "ip", "network", "gateway", "mask", "broadcast" }
for _, field in ipairs(fields) do
if not hiddenFields[field] then
local val = currentTooltip[field]
if val and val ~= "" then
table.insert(colKeys, ui.label({
text = noctalia.tr("tooltip." .. field),
fontSize = detailsFontSize,
color = noctalia.getConfig("details_key_color") or "primary"
}))
table.insert(colValues, ui.label({
text = val,
fontSize = detailsFontSize,
color = noctalia.getConfig("details_value_color") or "on_surface"
}))
end
end
end
if #colKeys > 0 then
table.insert(content, ui.row({ gap = 12, align = "center", justify = "center" }, {
ui.column({ gap = 4, align = "start" }, colKeys),
ui.column({ gap = 4, align = "start" }, colValues)
}))
end
end
desktopWidget.render(ui.column({ gap = 12, align = "center" }, content))
end
-------------------------------------------------------------------------------
-- LIFECYCLE HOOKS
-------------------------------------------------------------------------------
--- Handler for IPC messages dispatched to this widget.
function onIpc(event, payload)
if noctalia.getConfig("mode") ~= "ipc" then return end
if event == "set" then
local myId = noctalia.getConfig("ipc_id") or "default"
local data = utils.handleIpcPayload(payload, myId)
if data then
currentIp = data.ip
currentIpcName = data.name
currentTooltip = data.tooltip
render()
end
end
end
--- Primary update entry point called periodically by Noctalia script runtime.
function update()
local mode = noctalia.getConfig("mode")
if mode == "interface" then
utils.fetchInterfaceIp(noctalia.getConfig("iface"), function(ip, tooltip)
currentIp = ip
currentTooltip = tooltip
render()
end)
elseif mode == "custom_command" then
utils.fetchCustomCommandIp(noctalia.getConfig("custom_command"), function(ip, tooltip)
currentIp = ip
currentTooltip = tooltip
render()
end)
end
end
--- Config change handler called automatically when user alters widget settings.
function onConfigChanged()
local mode = noctalia.getConfig("mode")
currentIp = ""
currentIpcName = ""
currentTooltip = nil
if mode == "interface" or mode == "custom_command" then
local interval = noctalia.getConfig("refresh_interval") or 60
noctalia.setUpdateInterval(interval * 1000)
update()
else
-- IPC mode doesn't need periodic updates
noctalia.setUpdateInterval(0)
render()
end
end
-- Initial setup upon loading widget
onConfigChanged()