Merge pull request #357 from HamishFleming/fix/#242/apt-widget

fix(apt-widget): Fixed nil value (buttons) -Also replaces awful.util with gears
This commit is contained in:
streetturtle 2023-07-16 20:51:38 -04:00 committed by GitHub
commit cd0e1a8a3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 311 additions and 290 deletions

View File

@ -15,335 +15,356 @@ local naughty = require("naughty")
local gears = require("gears") local gears = require("gears")
local beautiful = require("beautiful") local beautiful = require("beautiful")
--- Utility Function to handle alternative paths
local function script_path()
local str = debug.getinfo(2, "S").source:sub(2)
return str:match("(.*/)")
end
local HOME_DIR = os.getenv("HOME") local HOME_DIR = os.getenv("HOME")
local WIDGET_DIR = HOME_DIR .. '/.config/awesome/awesome-wm-widgets/apt-widget' local WIDGET_DIR = script_path()
local ICONS_DIR = WIDGET_DIR .. '/icons/' local ICONS_DIR = WIDGET_DIR .. "/icons/"
local LIST_PACKAGES = [[sh -c "LC_ALL=c apt list --upgradable 2>/dev/null"]] local LIST_PACKAGES = [[sh -c "LC_ALL=c apt list --upgradable 2>/dev/null"]]
--- Utility function to show warning messages --- Utility function to show warning messages
local function show_warning(message) local function show_warning(message)
naughty.notify{ naughty.notify({
preset = naughty.config.presets.critical, preset = naughty.config.presets.critical,
title = 'Docker Widget', title = "Docker Widget",
text = message} text = message,
})
end end
local wibox_popup = wibox { local wibox_popup = wibox({
ontop = true, ontop = true,
visible = false, visible = false,
shape = function(cr, width, height) shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, 4) gears.shape.rounded_rect(cr, width, height, 4)
end, end,
border_width = 1, border_width = 1,
border_color = beautiful.bg_focus, border_color = beautiful.bg_focus,
max_widget_size = 500, max_widget_size = 500,
height = 500, height = 500,
width = 300, width = 300,
} })
local apt_widget = wibox.widget { local apt_widget = wibox.widget({
{ {
{ {
id = 'icon', id = "icon",
widget = wibox.widget.imagebox widget = wibox.widget.imagebox,
}, },
margins = 4, margins = 4,
layout = wibox.container.margin layout = wibox.container.margin,
}, },
layout = wibox.layout.fixed.horizontal, layout = wibox.layout.fixed.horizontal,
set_icon = function(self, new_icon) set_icon = function(self, new_icon)
self:get_children_by_id("icon")[1].image = new_icon self:get_children_by_id("icon")[1].image = new_icon
end end,
} })
local apt_widget_button = wibox.widget({
{
apt_widget,
widget = wibox.container.margin,
},
widget = clickable_container,
})
--- Parses the line and creates the package table out of it --- Parses the line and creates the package table out of it
--- yaru-theme-sound/focal-updates,focal-updates 20.04.10.1 all [upgradable from: 20.04.8] --- yaru-theme-sound/focal-updates,focal-updates 20.04.10.1 all [upgradable from: 20.04.8]
local parse_package = function(line) local parse_package = function(line)
local name,_,nv,type,ov = line:match('(.*)%/(.*)%s(.*)%s(.*)%s%[upgradable from: (.*)]') local name, _, nv, type, ov = line:match("(.*)%/(.*)%s(.*)%s(.*)%s%[upgradable from: (.*)]")
if name == nil then return nil end if name == nil then
return nil
end
local package = { local package = {
name = name, name = name,
new_version = nv, new_version = nv,
type = type, type = type,
old_version = ov old_version = ov,
} }
return package return package
end end
local function worker(user_args) local function worker(user_args)
local args = user_args or {}
local args = user_args or {} local icon = args.icon or ICONS_DIR .. "white-black.svg"
local icon = args.icon or ICONS_DIR .. 'white-black.svg' apt_widget:set_icon(icon)
apt_widget:set_icon(icon) local pointer = 0
local min_widgets = 5
local carousel = false
local pointer = 0 local function rebuild_widget(containers, errors, _, _)
local min_widgets = 5 local to_update = {}
local carousel = false
local function rebuild_widget(containers, errors, _, _) if errors ~= "" then
show_warning(errors)
return
end
local to_update = {} local rows = wibox.layout.fixed.vertical()
rows:connect_signal("button::press", function(_, _, _, button)
if carousel then
if button == 4 then -- up scrolling
local cnt = #rows.children
local first_widget = rows.children[1]
rows:insert(cnt + 1, first_widget)
rows:remove(1)
elseif button == 5 then -- down scrolling
local cnt = #rows.children
local last_widget = rows.children[cnt]
rows:insert(1, last_widget)
rows:remove(cnt + 1)
end
else
if button == 5 then -- up scrolling
if pointer < #rows.children and ((#rows.children - pointer) >= min_widgets) then
pointer = pointer + 1
rows.children[pointer].visible = false
end
elseif button == 4 then -- down scrolling
if pointer > 0 then
rows.children[pointer].visible = true
pointer = pointer - 1
end
end
end
end)
if errors ~= '' then for line in containers:gmatch("[^\r\n]+") do
show_warning(errors) local package = parse_package(line)
return
end
local rows = wibox.layout.fixed.vertical() if package ~= nil then
rows:connect_signal("button::press", function(_,_,_,button) local refresh_button = wibox.widget({
if carousel then {
if button == 4 then -- up scrolling {
local cnt = #rows.children id = "icon",
local first_widget = rows.children[1] image = ICONS_DIR .. "refresh-cw.svg",
rows:insert(cnt+1, first_widget) resize = false,
rows:remove(1) widget = wibox.widget.imagebox,
elseif button == 5 then -- down scrolling },
local cnt = #rows.children margins = 4,
local last_widget = rows.children[cnt] widget = wibox.container.margin,
rows:insert(1, last_widget) },
rows:remove(cnt+1) shape = gears.shape.circle,
end opacity = 0.5,
else widget = wibox.container.background,
if button == 5 then -- up scrolling })
if pointer < #rows.children and ((#rows.children - pointer) >= min_widgets) then local old_cursor, old_wibox
pointer = pointer + 1 refresh_button:connect_signal("mouse::enter", function(c)
rows.children[pointer].visible = false c:set_opacity(1)
end c:emit_signal("widget::redraw_needed")
elseif button == 4 then -- down scrolling local wb = mouse.current_wibox
if pointer > 0 then old_cursor, old_wibox = wb.cursor, wb
rows.children[pointer].visible = true wb.cursor = "hand1"
pointer = pointer - 1 end)
end refresh_button:connect_signal("mouse::leave", function(c)
end c:set_opacity(0.5)
end c:emit_signal("widget::redraw_needed")
end) if old_wibox then
old_wibox.cursor = old_cursor
old_wibox = nil
end
end)
for line in containers:gmatch("[^\r\n]+") do local row = wibox.widget({
local package = parse_package(line) {
{
{
{
id = "checkbox",
checked = false,
color = beautiful.bg_normal,
paddings = 2,
shape = gears.shape.circle,
forced_width = 20,
forced_height = 20,
check_color = beautiful.fg_urgent,
border_color = beautiful.bg_urgent,
border_width = 1,
widget = wibox.widget.checkbox,
},
valign = "center",
layout = wibox.container.place,
},
{
{
id = "name",
markup = "<b>" .. package["name"] .. "</b>",
widget = wibox.widget.textbox,
},
halign = "left",
layout = wibox.container.place,
},
{
refresh_button,
halign = "right",
valign = "center",
fill_horizontal = true,
layout = wibox.container.place,
},
spacing = 8,
layout = wibox.layout.fixed.horizontal,
},
margins = 8,
layout = wibox.container.margin,
},
id = "row",
bg = beautiful.bg_normal,
widget = wibox.container.background,
click = function(self, checked)
local a = self:get_children_by_id("checkbox")[1]
if checked == nil then
a:set_checked(not a.checked)
else
a:set_checked(checked)
end
if package ~= nil then if a.checked then
to_update[ package["name"] ] = self
else
to_update[ package["name"] ] = false
end
end,
update = function(self)
refresh_button:get_children_by_id("icon")[1]:set_image(ICONS_DIR .. "watch.svg")
self:get_children_by_id("name")[1]:set_opacity(0.4)
self:get_children_by_id("name")[1]:emit_signal("widget::redraw_needed")
local refresh_button = wibox.widget { spawn.easy_async(
{ string.format([[sh -c 'yes | aptdcon --hide-terminal -u %s']], package["name"]),
{ function(stdout, stderr) -- luacheck:ignore 212
id = 'icon', rows:remove_widgets(self)
image = ICONS_DIR .. 'refresh-cw.svg', end
resize = false, )
widget = wibox.widget.imagebox end,
}, })
margins = 4,
widget = wibox.container.margin
},
shape = gears.shape.circle,
opacity = 0.5,
widget = wibox.container.background
}
local old_cursor, old_wibox
refresh_button:connect_signal("mouse::enter", function(c)
c:set_opacity(1)
c:emit_signal('widget::redraw_needed')
local wb = mouse.current_wibox
old_cursor, old_wibox = wb.cursor, wb
wb.cursor = "hand1"
end)
refresh_button:connect_signal("mouse::leave", function(c)
c:set_opacity(0.5)
c:emit_signal('widget::redraw_needed')
if old_wibox then
old_wibox.cursor = old_cursor
old_wibox = nil
end
end)
local row = wibox.widget { row:connect_signal("mouse::enter", function(c)
{ c:set_bg(beautiful.bg_focus)
{ end)
{ row:connect_signal("mouse::leave", function(c)
{ c:set_bg(beautiful.bg_normal)
id = 'checkbox', end)
checked = false,
color = beautiful.bg_normal,
paddings = 2,
shape = gears.shape.circle,
forced_width = 20,
forced_height = 20,
check_color = beautiful.fg_urgent,
border_color = beautiful.bg_urgent,
border_width = 1,
widget = wibox.widget.checkbox
},
valign = 'center',
layout = wibox.container.place,
},
{
{
id = 'name',
markup = '<b>' .. package['name'] .. '</b>',
widget = wibox.widget.textbox
},
halign = 'left',
layout = wibox.container.place
},
{
refresh_button,
halign = 'right',
valign = 'center',
fill_horizontal = true,
layout = wibox.container.place,
},
spacing = 8,
layout = wibox.layout.fixed.horizontal
},
margins = 8,
layout = wibox.container.margin
},
id = 'row',
bg = beautiful.bg_normal,
widget = wibox.container.background,
click = function(self, checked)
local a = self:get_children_by_id('checkbox')[1]
if checked == nil then
a:set_checked(not a.checked)
else
a:set_checked(checked)
end
if a.checked then row:connect_signal("button::press", function(c, _, _, button)
to_update[package['name']] = self if button == 1 then
else c:click()
to_update[package['name']] = false end
end end)
end,
update = function(self)
refresh_button:get_children_by_id('icon')[1]:set_image(ICONS_DIR .. 'watch.svg')
self:get_children_by_id('name')[1]:set_opacity(0.4)
self:get_children_by_id('name')[1]:emit_signal('widget::redraw_needed')
spawn.easy_async( refresh_button:buttons(gears.table.join(awful.button({}, 1, function()
string.format([[sh -c 'yes | aptdcon --hide-terminal -u %s']], package['name']), row:update()
function(stdout, stderr) -- luacheck:ignore 212 end)))
rows:remove_widgets(self)
end)
end rows:add(row)
} end
end
row:connect_signal("mouse::enter", function(c) local header_checkbox = wibox.widget({
c:set_bg(beautiful.bg_focus) checked = false,
end) color = beautiful.bg_normal,
row:connect_signal("mouse::leave", function(c) paddings = 2,
c:set_bg(beautiful.bg_normal) shape = gears.shape.circle,
end) forced_width = 20,
forced_height = 20,
check_color = beautiful.fg_urgent,
border_color = beautiful.bg_urgent,
border_width = 1,
widget = wibox.widget.checkbox,
})
header_checkbox:connect_signal("button::press", function(c)
c:set_checked(not c.checked)
local cbs = rows.children
for _, v in ipairs(cbs) do
v:click(c.checked)
end
end)
row:connect_signal("button::press", function(c, _, _, button) local header_refresh_icon = wibox.widget({
if button == 1 then c:click() end image = ICONS_DIR .. "refresh-cw.svg",
end) resize = false,
widget = wibox.widget.imagebox,
})
header_refresh_icon:buttons(gears.table.join(awful.button({}, 1, function()
print(#to_update)
for _, v in pairs(to_update) do
if v ~= nil then
v:update()
end
end
end)))
refresh_button:buttons(awful.util.table.join(awful.button({}, 1, function() local header_row = wibox.widget({
row:update() {
end))) {
{
header_checkbox,
valign = "center",
layout = wibox.container.place,
},
{
{
id = "name",
markup = "<b>" .. #rows.children .. "</b> packages to update",
widget = wibox.widget.textbox,
},
halign = "center",
layout = wibox.container.place,
},
{
header_refresh_icon,
halign = "right",
valign = "center",
layout = wibox.container.place,
},
layout = wibox.layout.align.horizontal,
},
margins = 8,
layout = wibox.container.margin,
},
bg = beautiful.bg_normal,
widget = wibox.container.background,
})
rows:add(row) wibox_popup:setup({
end header_row,
end rows,
layout = wibox.layout.fixed.vertical,
})
end
apt_widget:buttons(gears.table.join(awful.button({}, 1, function()
if wibox_popup.visible then
wibox_popup.visible = not wibox_popup.visible
else
spawn.easy_async(LIST_PACKAGES, function(stdout, stderr)
rebuild_widget(stdout, stderr)
wibox_popup.visible = true
awful.placement.top(wibox_popup, { margins = { top = 20 }, parent = mouse })
end)
end
end)))
local header_checkbox = wibox.widget { wibox_popup:connect_signal("mouse::leave", function()
checked = false, if wibox_popup.visible then
color = beautiful.bg_normal, wibox_popup.visible = false
paddings = 2, end
shape = gears.shape.circle, end)
forced_width = 20,
forced_height = 20,
check_color = beautiful.fg_urgent,
border_color = beautiful.bg_urgent,
border_width = 1,
widget = wibox.widget.checkbox
}
header_checkbox:connect_signal("button::press", function(c)
c:set_checked(not c.checked)
local cbs = rows.children
for _,v in ipairs(cbs) do
v:click(c.checked)
end
end)
local header_refresh_icon = wibox.widget { return apt_widget_button
image = ICONS_DIR .. 'refresh-cw.svg',
resize = false,
widget = wibox.widget.imagebox
}
header_refresh_icon:buttons(awful.util.table.join(awful.button({}, 1, function()
print(#to_update)
for _,v in pairs(to_update) do
if v ~= nil then
v:update()
end
end
end)))
local header_row = wibox.widget {
{
{
{
header_checkbox,
valign = 'center',
layout = wibox.container.place,
},
{
{
id = 'name',
markup = '<b>' .. #rows.children .. '</b> packages to update',
widget = wibox.widget.textbox
},
halign = 'center',
layout = wibox.container.place
},
{
header_refresh_icon,
halign = 'right',
valign = 'center',
layout = wibox.container.place,
},
layout = wibox.layout.align.horizontal
},
margins = 8,
layout = wibox.container.margin
},
bg = beautiful.bg_normal,
widget = wibox.container.background
}
wibox_popup:setup {
header_row,
rows,
layout = wibox.layout.fixed.vertical
}
end
apt_widget:buttons(
awful.util.table.join(
awful.button({}, 1, function()
if wibox_popup.visible then
wibox_popup.visible = not wibox_popup.visible
else
spawn.easy_async(LIST_PACKAGES,
function(stdout, stderr)
rebuild_widget(stdout, stderr)
wibox_popup.visible = true
awful.placement.top(wibox_popup, { margins = { top = 20 }, parent = mouse})
end)
end
end)
)
)
return apt_widget
end end
return setmetatable(apt_widget, { __call = function(_, ...) return worker(...) end }) return setmetatable(apt_widget, {
__call = function(_, ...)
return worker(...)
end,
})