added some keyboard shortcuts to README and lots of cleanup
@@ -1,124 +0,0 @@
|
||||
-------------------------------------------------
|
||||
-- Battery Widget for Awesome Window Manager
|
||||
-- Shows the battery status using the ACPI tool
|
||||
-- More details could be found here:
|
||||
-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/battery-widget
|
||||
-- @author Pavel Makhov
|
||||
-- @copyright 2017 Pavel Makhov
|
||||
-------------------------------------------------
|
||||
local awful = require('awful')
|
||||
local watch = require('awful.widget.watch')
|
||||
local wibox = require('wibox')
|
||||
local beautiful = require('beautiful')
|
||||
local dpi = require('beautiful').xresources.apply_dpi
|
||||
|
||||
-- acpi sample outputs
|
||||
-- Battery 0: Discharging, 75%, 01:51:38 remaining
|
||||
-- Battery 0: Charging, 53%, 00:57:43 until charged
|
||||
|
||||
local percentage = wibox.widget.textbox()
|
||||
local battery_icon = wibox.widget.textbox()
|
||||
battery_icon.font = beautiful.icon_font
|
||||
|
||||
local battery_popup = awful.tooltip({
|
||||
objects = {percentage},
|
||||
mode = 'outside',
|
||||
align = 'left',
|
||||
preferred_positions = {'right', 'left', 'top', 'bottom'}
|
||||
})
|
||||
|
||||
watch('acpi -i', 10, function(_, stdout)
|
||||
local battery_info = {}
|
||||
local capacities = {}
|
||||
for s in stdout:gmatch('[^\r\n]+') do
|
||||
local status, charge_str, time = string.match(s, '.+: (%a+), (%d?%d?%d)%%,?.*')
|
||||
if status ~= nil then
|
||||
table.insert(battery_info, {
|
||||
status = status,
|
||||
charge = tonumber(charge_str)
|
||||
})
|
||||
else
|
||||
local cap_str = string.match(s, '.+:.+last full capacity (%d+)')
|
||||
table.insert(capacities, tonumber(cap_str))
|
||||
end
|
||||
end
|
||||
|
||||
local capacity = 0
|
||||
for _, cap in ipairs(capacities) do
|
||||
capacity = capacity + cap
|
||||
end
|
||||
|
||||
local charge = 0
|
||||
local status
|
||||
for i, batt in ipairs(battery_info) do
|
||||
if batt.charge >= charge then
|
||||
status = batt.status -- use most charged battery status
|
||||
-- this is arbitrary, and maybe another metric should be used
|
||||
end
|
||||
|
||||
charge = charge + batt.charge * capacities[i]
|
||||
end
|
||||
charge = charge / capacity
|
||||
|
||||
battery_popup.text = string.gsub(stdout, '\n$', '')
|
||||
percentage.text = math.floor(charge)
|
||||
|
||||
if status == 'Charging' then
|
||||
battery_icon.text = ''
|
||||
if math.floor(charge) <= 20 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 30 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 40 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 60 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 80 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 90 then
|
||||
--battery_icon.text = ''
|
||||
battery_icon.text = '90'
|
||||
elseif math.floor(charge) <= 100 then
|
||||
--battery_icon.text = ''
|
||||
battery_icon.text = '90'
|
||||
end
|
||||
elseif status == 'Full' then
|
||||
battery_icon.text = ''
|
||||
else
|
||||
if math.floor(charge) <= 10 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 20 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 30 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 40 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 50 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 60 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 60 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 80 then
|
||||
battery_icon.text = ''
|
||||
elseif math.floor(charge) <= 90 then
|
||||
battery_icon.text = ''
|
||||
battery_icon.text = '90'
|
||||
elseif math.floor(charge) <= 100 then
|
||||
battery_icon.text = ''
|
||||
battery_icon.text = '90'
|
||||
end
|
||||
end
|
||||
collectgarbage('collect')
|
||||
end)
|
||||
|
||||
return wibox.widget {
|
||||
wibox.widget{
|
||||
battery_icon,
|
||||
fg = beautiful.accent.hue_300,
|
||||
widget = wibox.container.background
|
||||
},
|
||||
percentage,
|
||||
spacing = dpi(2),
|
||||
layout = wibox.layout.fixed.horizontal
|
||||
}
|
@@ -1,52 +0,0 @@
|
||||
local awful = require("awful")
|
||||
local wibox = require('wibox')
|
||||
local mat_list_item = require('widget.material.list-item')
|
||||
local dpi = require('beautiful').xresources.apply_dpi
|
||||
local watch = require('awful.widget.watch')
|
||||
local beautiful = require('beautiful')
|
||||
|
||||
local battery_icon = wibox.widget.textbox()
|
||||
battery_icon.font = beautiful.icon_font
|
||||
local battery_widget = wibox.widget.textbox()
|
||||
battery_widget.align = 'center'
|
||||
battery_widget.valign = 'center'
|
||||
battery_widget.font = beautiful.font
|
||||
|
||||
local battery
|
||||
|
||||
function update_battery()
|
||||
awful.spawn.easy_async_with_shell("pamixer --get-volume", function(stdout)
|
||||
battery = stdout
|
||||
--battery = string.match(stdout, '(%d?%d?%d)%%')
|
||||
awful.spawn.easy_async_with_shell("bash -c 'pacmd list-sinks | awk '/muted/ { print $2 }''", function(muted)
|
||||
--muted = string.gsub(muted, "%s+", "")
|
||||
muted = 'no'
|
||||
if muted == 'muted:no' and (battery > '50' or battery == '100') then
|
||||
battery_icon.text = '墳'
|
||||
elseif muted == 'muted:no' and battery <= '50' and battery > '0' then
|
||||
battery_icon.text = '奔'
|
||||
elseif muted == 'muted:yes' then
|
||||
battery_icon.text = '婢'
|
||||
elseif battery == '0' then
|
||||
battery_icon.text = '奄'
|
||||
end
|
||||
battery_widget.text = battery
|
||||
end)
|
||||
collectgarbage('collect')
|
||||
end)
|
||||
end
|
||||
|
||||
watch('bash -c', 3, function(_, stdout)
|
||||
update_battery()
|
||||
end)
|
||||
|
||||
return wibox.widget {
|
||||
wibox.widget{
|
||||
battery_icon,
|
||||
fg = beautiful.accent.hue_100,
|
||||
widget = wibox.container.background
|
||||
},
|
||||
battery_widget,
|
||||
spacing = dpi(2),
|
||||
layout = wibox.layout.fixed.horizontal
|
||||
}
|
@@ -1,191 +0,0 @@
|
||||
-------------------------------------------------
|
||||
-- Battery Widget for Awesome Window Manager
|
||||
-- Shows the battery status using the ACPI tool
|
||||
-- More details could be found here:
|
||||
-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/battery-widget
|
||||
|
||||
-- @author Pavel Makhov
|
||||
-- @copyright 2017 Pavel Makhov
|
||||
-------------------------------------------------
|
||||
|
||||
local awful = require("awful")
|
||||
local naughty = require("naughty")
|
||||
local watch = require("awful.widget.watch")
|
||||
local wibox = require("wibox")
|
||||
local gfs = require("gears.filesystem")
|
||||
local dpi = require('beautiful').xresources.apply_dpi
|
||||
|
||||
-- acpi sample outputs
|
||||
-- Battery 0: Discharging, 75%, 01:51:38 remaining
|
||||
-- Battery 0: Charging, 53%, 00:57:43 until charged
|
||||
|
||||
local HOME = os.getenv("HOME")
|
||||
|
||||
local battery_widget = {}
|
||||
local function worker(args)
|
||||
local args = args or {}
|
||||
|
||||
local bat_num = '1'
|
||||
local font = args.font or 'Play 8'
|
||||
local path_to_icons = args.path_to_icons or "/usr/share/icons/Arc/status/symbolic/"
|
||||
local show_current_level = args.show_current_level or false
|
||||
local margin_left = args.margin_left or 0
|
||||
local margin_right = args.margin_right or 0
|
||||
|
||||
local display_notification = args.display_notification or false
|
||||
local position = args.notification_position or "top_right"
|
||||
local timeout = args.timeout or 10
|
||||
|
||||
local warning_msg_title = args.warning_msg_title or 'Huston, we have a problem'
|
||||
local warning_msg_text = args.warning_msg_text or 'Battery is dying'
|
||||
local warning_msg_position = args.warning_msg_position or 'bottom_right'
|
||||
local warning_msg_icon = args.warning_msg_icon or HOME .. '/.config/awesome/awesome-wm-widgets/batteryarc-widget/spaceman.jpg'
|
||||
local enable_battery_warning = args.enable_battery_warning
|
||||
if enable_battery_warning == nil then
|
||||
enable_battery_warning = true
|
||||
end
|
||||
|
||||
local bat_expr = 'Battery ' .. bat_num
|
||||
if not gfs.dir_readable(path_to_icons) then
|
||||
naughty.notify{
|
||||
title = "Battery Widget",
|
||||
text = "Folder with icons doesn't exist: " .. path_to_icons,
|
||||
preset = naughty.config.presets.critical
|
||||
}
|
||||
end
|
||||
|
||||
local icon_widget = wibox.widget {
|
||||
{
|
||||
id = "icon",
|
||||
widget = wibox.widget.imagebox,
|
||||
resize = false
|
||||
},
|
||||
layout = wibox.container.margin(_, 0, 0, 3)
|
||||
}
|
||||
local level_widget = wibox.widget {
|
||||
font = font,
|
||||
widget = wibox.widget.textbox
|
||||
}
|
||||
|
||||
battery_widget = wibox.widget {
|
||||
icon_widget,
|
||||
level_widget,
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
}
|
||||
-- Popup with battery info
|
||||
-- One way of creating a pop-up notification - naughty.notify
|
||||
local notification
|
||||
local function show_battery_status(batteryType)
|
||||
awful.spawn.easy_async('bash -c "acpi | grep \'' .. bat_expr .. '\'"',
|
||||
function(stdout, _, _, _)
|
||||
naughty.destroy(notification)
|
||||
notification = naughty.notify{
|
||||
text = stdout,
|
||||
title = "Battery status",
|
||||
icon = path_to_icons .. batteryType .. ".svg",
|
||||
icon_size = dpi(16),
|
||||
position = position,
|
||||
timeout = 5, hover_timeout = 0.5,
|
||||
width = 200,
|
||||
screen = mouse.screen
|
||||
}
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
-- Alternative to naughty.notify - tooltip. You can compare both and choose the preferred one
|
||||
--battery_popup = awful.tooltip({objects = {battery_widget}})
|
||||
|
||||
-- To use colors from beautiful theme put
|
||||
-- following lines in rc.lua before require("battery"):
|
||||
-- beautiful.tooltip_fg = beautiful.fg_normal
|
||||
-- beautiful.tooltip_bg = beautiful.bg_normal
|
||||
|
||||
local function show_battery_warning()
|
||||
naughty.notify {
|
||||
icon = warning_msg_icon,
|
||||
icon_size = 100,
|
||||
text = warning_msg_text,
|
||||
title = warning_msg_title,
|
||||
timeout = 25, -- show the warning for a longer time
|
||||
hover_timeout = 0.5,
|
||||
position = warning_msg_position,
|
||||
bg = "#F06060",
|
||||
fg = "#EEE9EF",
|
||||
width = 300,
|
||||
screen = mouse.screen
|
||||
}
|
||||
end
|
||||
local last_battery_check = os.time()
|
||||
local batteryType = "battery-good-symbolic"
|
||||
|
||||
watch('bash -c "acpi -i | grep \'' .. bat_expr .. '\'"', timeout,
|
||||
function(widget, stdout, stderr, exitreason, exitcode)
|
||||
local battery_info = {}
|
||||
local capacities = {}
|
||||
for s in stdout:gmatch("[^\r\n]+") do
|
||||
local status, charge_str, time = string.match(s, '.+: (%a+), (%d?%d?%d)%%,?(.*)')
|
||||
if status ~= nil then
|
||||
table.insert(battery_info, {status = status, charge = tonumber(charge_str)})
|
||||
else
|
||||
local cap_str = string.match(s, '.+:.+last full capacity (%d+)')
|
||||
table.insert(capacities, tonumber(cap_str))
|
||||
end
|
||||
end
|
||||
|
||||
local capacity = 0
|
||||
for i, cap in ipairs(capacities) do
|
||||
capacity = capacity + cap
|
||||
end
|
||||
|
||||
local charge = 0
|
||||
local status
|
||||
for i, batt in ipairs(battery_info) do
|
||||
if batt.charge >= charge then
|
||||
status = batt.status -- use most charged battery status
|
||||
-- this is arbitrary, and maybe another metric should be used
|
||||
end
|
||||
|
||||
charge = charge + batt.charge * capacities[i]
|
||||
end
|
||||
charge = charge / capacity
|
||||
|
||||
if show_current_level then
|
||||
level_widget.text = string.format('%d%%', charge)
|
||||
end
|
||||
|
||||
if (charge >= 0 and charge < 15) then
|
||||
batteryType = "battery-empty%s-symbolic"
|
||||
if enable_battery_warning and status ~= 'Charging' and os.difftime(os.time(), last_battery_check) > 300 then
|
||||
-- if 5 minutes have elapsed since the last warning
|
||||
last_battery_check = os.time()
|
||||
|
||||
show_battery_warning()
|
||||
end
|
||||
elseif (charge >= 15 and charge < 40) then batteryType = "battery-caution%s-symbolic"
|
||||
elseif (charge >= 40 and charge < 60) then batteryType = "battery-low%s-symbolic"
|
||||
elseif (charge >= 60 and charge < 80) then batteryType = "battery-good%s-symbolic"
|
||||
elseif (charge >= 80 and charge <= 100) then batteryType = "battery-full%s-symbolic"
|
||||
end
|
||||
|
||||
if status == 'Charging' then
|
||||
batteryType = string.format(batteryType, '-charging')
|
||||
else
|
||||
batteryType = string.format(batteryType, '')
|
||||
end
|
||||
|
||||
widget.icon:set_image(path_to_icons .. batteryType .. ".svg")
|
||||
|
||||
-- Update popup text
|
||||
-- battery_popup.text = string.gsub(stdout, "\n$", "")
|
||||
end,
|
||||
icon_widget)
|
||||
|
||||
if display_notification then
|
||||
battery_widget:connect_signal("mouse::enter", function() show_battery_status(batteryType) end)
|
||||
battery_widget:connect_signal("mouse::leave", function() naughty.destroy(notification) end)
|
||||
end
|
||||
return wibox.container.margin(battery_widget, margin_left, margin_right)
|
||||
end
|
||||
|
||||
return setmetatable(battery_widget, { __call = function(_, ...) return worker(...) end })
|
@@ -1,53 +0,0 @@
|
||||
# Calendar Widget
|
||||
|
||||
Calendar widget for Awesome WM - slightly improved version of the `wibox.widget.calendar`.
|
||||
|
||||
## Features
|
||||
|
||||
- mouse support: scroll up - shows next month, scroll down - previous
|
||||
- themes:
|
||||
|
||||
| Name | Screenshot |
|
||||
|---|---|
|
||||
|nord (default) |  |
|
||||
| outrun |  |
|
||||
| light |  |
|
||||
| dark |  |
|
||||
|
||||
- setup widget placement
|
||||
|
||||
top center - in case you clock is centered:
|
||||
|
||||

|
||||
|
||||
top right - for default awesome config:
|
||||
|
||||

|
||||
|
||||
bottom right - in case your wibar at the bottom:
|
||||
|
||||

|
||||
|
||||
|
||||
## How to use
|
||||
|
||||
This widget needs an 'anchor' - another widget which triggers visibility of the calendar. Default `mytextclock` is the perfect candidate!
|
||||
Just after mytextclock is instantiated, create the widget and add the mouse listener to it.
|
||||
|
||||
```lua
|
||||
local calendar_widget = require("awesome-wm-widgets.calendar-widget.calendar")
|
||||
-- ...
|
||||
-- Create a textclock widget
|
||||
mytextclock = wibox.widget.textclock()
|
||||
-- default
|
||||
local cw = calendar_widget()
|
||||
-- or customized
|
||||
local cw = calendar_widget({
|
||||
theme = 'outrun',
|
||||
placement = 'bottom_right'
|
||||
})
|
||||
mytextclock:connect_signal("button::press",
|
||||
function(_, _, _, button)
|
||||
if button == 1 then cw.toggle() end
|
||||
end)
|
||||
```
|
@@ -1,235 +0,0 @@
|
||||
-------------------------------------------------
|
||||
-- Calendar Widget for Awesome Window Manager
|
||||
-- Shows the current month and supports scroll up/down to switch month
|
||||
-- More details could be found here:
|
||||
-- https://github.com/streetturtle/awesome-wm-widgets/tree/master/calendar-widget
|
||||
|
||||
-- @author Pavel Makhov
|
||||
-- @copyright 2019 Pavel Makhov
|
||||
-------------------------------------------------
|
||||
|
||||
local awful = require("awful")
|
||||
local beautiful = require("beautiful")
|
||||
local wibox = require("wibox")
|
||||
local gears = require("gears")
|
||||
local naughty = require("naughty")
|
||||
|
||||
local calendar_widget = {}
|
||||
|
||||
local function worker(args)
|
||||
|
||||
local calendar_themes = {
|
||||
nord = {
|
||||
bg = '#2E3440',
|
||||
fg = '#D8DEE9',
|
||||
focus_date_bg = '#88C0D0',
|
||||
focus_date_fg = '#000000',
|
||||
weekend_day_bg = '#3B4252',
|
||||
weekday_fg = '#88C0D0',
|
||||
header_fg = '#E5E9F0',
|
||||
border = '#4C566A'
|
||||
},
|
||||
outrun = {
|
||||
bg = '#0d0221',
|
||||
fg = '#D8DEE9',
|
||||
focus_date_bg = '#650d89',
|
||||
focus_date_fg = '#2de6e2',
|
||||
weekend_day_bg = '#261447',
|
||||
weekday_fg = '#2de6e2',
|
||||
header_fg = '#f6019d',
|
||||
border = '#261447'
|
||||
},
|
||||
dark = {
|
||||
bg = '#000000',
|
||||
fg = '#ffffff',
|
||||
focus_date_bg = '#ffffff',
|
||||
focus_date_fg = '#000000',
|
||||
weekend_day_bg = '#444444',
|
||||
weekday_fg = '#ffffff',
|
||||
header_fg = '#ffffff',
|
||||
border = '#333333'
|
||||
},
|
||||
light = {
|
||||
bg = '#ffffff',
|
||||
fg = '#000000',
|
||||
focus_date_bg = '#000000',
|
||||
focus_date_fg = '#ffffff',
|
||||
weekend_day_bg = '#AAAAAA',
|
||||
weekday_fg = '#000000',
|
||||
header_fg = '#000000',
|
||||
border = '#CCCCCC'
|
||||
},
|
||||
monokai = {
|
||||
bg = '#272822',
|
||||
fg = '#F8F8F2',
|
||||
focus_date_bg = '#AE81FF',
|
||||
focus_date_fg = '#ffffff',
|
||||
weekend_day_bg = '#75715E',
|
||||
weekday_fg = '#FD971F',
|
||||
header_fg = '#F92672',
|
||||
border = '#75715E'
|
||||
}
|
||||
}
|
||||
|
||||
local args = args or {}
|
||||
|
||||
if args.theme ~= nil and calendar_themes[args.theme] == nil then
|
||||
naughty.notify({
|
||||
preset = naughty.config.presets.critical,
|
||||
title = 'Calendar Widget',
|
||||
text = 'Theme "' .. args.theme .. '" not found, fallback to default'})
|
||||
args.theme = 'nord'
|
||||
end
|
||||
|
||||
local theme = args.theme or 'nord'
|
||||
local placement = args.placement or 'top'
|
||||
|
||||
|
||||
local styles = {}
|
||||
local function rounded_shape(size)
|
||||
return function(cr, width, height)
|
||||
gears.shape.rounded_rect(cr, width, height, size)
|
||||
end
|
||||
end
|
||||
|
||||
styles.month = {
|
||||
padding = 4,
|
||||
bg_color = calendar_themes[theme].bg,
|
||||
border_width = 0,
|
||||
}
|
||||
|
||||
styles.normal = {
|
||||
markup = function(t) return t end,
|
||||
shape = rounded_shape(4)
|
||||
}
|
||||
|
||||
styles.focus = {
|
||||
fg_color = calendar_themes[theme].focus_date_fg,
|
||||
bg_color = calendar_themes[theme].focus_date_bg,
|
||||
markup = function(t) return '<b>' .. t .. '</b>' end,
|
||||
shape = rounded_shape(4)
|
||||
}
|
||||
|
||||
styles.header = {
|
||||
fg_color = calendar_themes[theme].header_fg,
|
||||
bg_color = calendar_themes[theme].bg,
|
||||
markup = function(t) return '<b>' .. t .. '</b>' end
|
||||
}
|
||||
|
||||
styles.weekday = {
|
||||
fg_color = calendar_themes[theme].weekday_fg,
|
||||
bg_color = calendar_themes[theme].bg,
|
||||
markup = function(t) return '<b>' .. t .. '</b>' end,
|
||||
}
|
||||
|
||||
local function decorate_cell(widget, flag, date)
|
||||
if flag == 'monthheader' and not styles.monthheader then
|
||||
flag = 'header'
|
||||
end
|
||||
|
||||
-- highlight only today's day
|
||||
if flag == 'focus' then
|
||||
local today = os.date('*t')
|
||||
if today.month ~= date.month then
|
||||
flag = 'normal'
|
||||
end
|
||||
end
|
||||
|
||||
local props = styles[flag] or {}
|
||||
if props.markup and widget.get_text and widget.set_markup then
|
||||
widget:set_markup(props.markup(widget:get_text()))
|
||||
end
|
||||
-- Change bg color for weekends
|
||||
local d = { year = date.year, month = (date.month or 1), day = (date.day or 1) }
|
||||
local weekday = tonumber(os.date('%w', os.time(d)))
|
||||
local default_bg = (weekday == 0 or weekday == 6) and calendar_themes[theme].weekend_day_bg or calendar_themes[theme].bg
|
||||
local ret = wibox.widget {
|
||||
{
|
||||
{
|
||||
widget,
|
||||
halign = 'center',
|
||||
widget = wibox.container.place
|
||||
},
|
||||
margins = (props.padding or 2) + (props.border_width or 0),
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
shape = props.shape,
|
||||
shape_border_color = props.border_color or '#000000',
|
||||
shape_border_width = props.border_width or 0,
|
||||
fg = props.fg_color or calendar_themes[theme].fg,
|
||||
bg = props.bg_color or default_bg,
|
||||
widget = wibox.container.background
|
||||
}
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
local cal = wibox.widget {
|
||||
date = os.date('*t'),
|
||||
font = beautiful.get_font(),
|
||||
fn_embed = decorate_cell,
|
||||
long_weekdays = true,
|
||||
widget = wibox.widget.calendar.month
|
||||
}
|
||||
|
||||
local popup = awful.popup {
|
||||
ontop = true,
|
||||
visible = false,
|
||||
shape = gears.shape.rounded_rect,
|
||||
offset = { y = 5 },
|
||||
border_width = 1,
|
||||
border_color = calendar_themes[theme].border,
|
||||
widget = cal
|
||||
}
|
||||
|
||||
popup:buttons(
|
||||
awful.util.table.join(
|
||||
awful.button({}, 4, function()
|
||||
local a = cal:get_date()
|
||||
a.month = a.month + 1
|
||||
cal:set_date(nil)
|
||||
cal:set_date(a)
|
||||
popup:set_widget(cal)
|
||||
end),
|
||||
awful.button({}, 5, function()
|
||||
local a = cal:get_date()
|
||||
a.month = a.month - 1
|
||||
cal:set_date(nil)
|
||||
cal:set_date(a)
|
||||
popup:set_widget(cal)
|
||||
end)
|
||||
)
|
||||
)
|
||||
|
||||
function calendar_widget.toggle()
|
||||
|
||||
if popup.visible then
|
||||
-- to faster render the calendar refresh it and just hide
|
||||
cal:set_date(nil) -- the new date is not set without removing the old one
|
||||
cal:set_date(os.date('*t'))
|
||||
popup:set_widget(nil) -- just in case
|
||||
popup:set_widget(cal)
|
||||
popup.visible = not popup.visible
|
||||
else
|
||||
if placement == 'top' then
|
||||
awful.placement.top(popup, { margins = { top = 30 }, parent = awful.screen.focused() })
|
||||
elseif placement == 'top_right' then
|
||||
awful.placement.top_right(popup, { margins = { top = 30, right = 10}, parent = awful.screen.focused() })
|
||||
elseif placement == 'bottom_right' then
|
||||
awful.placement.bottom_right(popup, { margins = { bottom = 30, right = 10}, parent = awful.screen.focused() })
|
||||
else
|
||||
awful.placement.top(popup, { margins = { top = 30 }, parent = awful.screen.focused() })
|
||||
end
|
||||
|
||||
popup.visible = true
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return calendar_widget
|
||||
|
||||
end
|
||||
|
||||
return setmetatable(calendar_widget, { __call = function(_, ...)
|
||||
return worker(...)
|
||||
end })
|
Before Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 130 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 9.6 KiB |
@@ -1,70 +0,0 @@
|
||||
local awful = require('awful')
|
||||
local gears = require('gears')
|
||||
local wibox = require('wibox')
|
||||
local beautiful = require('beautiful')
|
||||
local icons = require('theme.icons')
|
||||
local clickable_container = require('widget.material.clickable-container')
|
||||
local dpi = require('beautiful').xresources.apply_dpi
|
||||
|
||||
local styles = {}
|
||||
local function rounded_shape(size, partial)
|
||||
if partial then
|
||||
return function(cr, width, height)
|
||||
gears.shape.rectangle(cr, width + 5, height, 11)
|
||||
end
|
||||
else
|
||||
return function(cr, width, height)
|
||||
gears.shape.rectangle(cr, width, height, size)
|
||||
end
|
||||
end
|
||||
end
|
||||
styles.month = {padding = 5, bg_color = '#555555', shape = rounded_shape(10)}
|
||||
styles.normal = {shape = rounded_shape(5)}
|
||||
styles.focus = {
|
||||
fg_color = beautiful.primary.hue_400, -- Current day Color
|
||||
markup = function(t) return '<b>' .. t .. '</b>' end,
|
||||
shape = rounded_shape(5, true)
|
||||
}
|
||||
styles.header = {
|
||||
fg_color = beautiful.primary.hue_200, -- Month Name Color
|
||||
markup = function(t) return '<b>' .. t .. '</b>' end,
|
||||
shape = rounded_shape(10)
|
||||
}
|
||||
styles.weekday = {
|
||||
fg_color = beautiful.background.hue_50, -- Day Color
|
||||
markup = function(t) return '<b>' .. t .. '</b>' end,
|
||||
shape = rounded_shape(5)
|
||||
}
|
||||
local function decorate_cell(widget, flag, date)
|
||||
if flag == 'monthheader' and not styles.monthheader then flag = 'header' end
|
||||
local props = styles[flag] or {}
|
||||
if props.markup and widget.get_text and widget.set_markup then
|
||||
widget:set_markup(props.markup(widget:get_text()))
|
||||
end
|
||||
local d = {
|
||||
year = date.year,
|
||||
month = (date.month or 1),
|
||||
day = (date.day or 1)
|
||||
}
|
||||
local weekday = tonumber(os.date('%w', os.time(d)))
|
||||
local ret = wibox.widget {
|
||||
{
|
||||
widget,
|
||||
margins = (props.padding or 2) + (props.border_width or 0),
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
fg = props.fg_color or '#999999',
|
||||
widget = wibox.container.background
|
||||
}
|
||||
return ret
|
||||
end
|
||||
|
||||
local cal = wibox.widget {
|
||||
date = os.date('*t'),
|
||||
font = 'Roboto 10',
|
||||
fn_embed = decorate_cell,
|
||||
start_sunday = true,
|
||||
widget = wibox.widget.calendar.month
|
||||
}
|
||||
|
||||
return cal
|
@@ -8,7 +8,7 @@ local dpi = require('beautiful').xresources.apply_dpi
|
||||
local wibox = require('wibox')
|
||||
local gears = require('gears')
|
||||
local beautiful = require('beautiful')
|
||||
local mat_colors = require('theme.mat-colors')
|
||||
local mat_colors = require('theme.color-schemes')
|
||||
-- Local declarations
|
||||
|
||||
local mat_slider = {
|
||||
|
@@ -1,560 +0,0 @@
|
||||
-------------------------------------------------
|
||||
-- Weather Widget based on the OpenWeatherMap
|
||||
-- https://openweathermap.org/
|
||||
--
|
||||
-- @author Pavel Makhov
|
||||
-- @copyright 2020 Pavel Makhov
|
||||
-------------------------------------------------
|
||||
local awful = require("awful")
|
||||
local watch = require("awful.widget.watch")
|
||||
local json = require("json")
|
||||
local naughty = require("naughty")
|
||||
local wibox = require("wibox")
|
||||
local gears = require("gears")
|
||||
local beautiful = require("beautiful")
|
||||
|
||||
local HOME_DIR = os.getenv("HOME")
|
||||
local WIDGET_DIR = HOME_DIR .. '/.config/awesome/awesome-wm-widgets/weather-widget'
|
||||
local GET_FORECAST_CMD = [[bash -c "curl -s --show-error -X GET '%s'"]]
|
||||
|
||||
local function show_warning(message)
|
||||
naughty.notify {
|
||||
preset = naughty.config.presets.critical,
|
||||
title = 'Weather Widget',
|
||||
text = message
|
||||
}
|
||||
end
|
||||
|
||||
local weather_widget = {}
|
||||
local warning_shown = false
|
||||
local tooltip = awful.tooltip {
|
||||
mode = 'outside',
|
||||
preferred_positions = {'bottom'}
|
||||
}
|
||||
|
||||
local weather_popup = awful.popup {
|
||||
ontop = true,
|
||||
visible = false,
|
||||
shape = gears.shape.rounded_rect,
|
||||
border_width = 1,
|
||||
border_color = beautiful.bg_focus,
|
||||
maximum_width = 400,
|
||||
offset = {y = 5},
|
||||
widget = {}
|
||||
}
|
||||
|
||||
--- Maps openWeatherMap icon name to file name w/o extension
|
||||
local icon_map = {
|
||||
["01d"] = "clear-sky",
|
||||
["02d"] = "few-clouds",
|
||||
["03d"] = "scattered-clouds",
|
||||
["04d"] = "broken-clouds",
|
||||
["09d"] = "shower-rain",
|
||||
["10d"] = "rain",
|
||||
["11d"] = "thunderstorm",
|
||||
["13d"] = "snow",
|
||||
["50d"] = "mist",
|
||||
["01n"] = "clear-sky-night",
|
||||
["02n"] = "few-clouds-night",
|
||||
["03n"] = "scattered-clouds-night",
|
||||
["04n"] = "broken-clouds-night",
|
||||
["09n"] = "shower-rain-night",
|
||||
["10n"] = "rain-night",
|
||||
["11n"] = "thunderstorm-night",
|
||||
["13n"] = "snow-night",
|
||||
["50n"] = "mist-night"
|
||||
}
|
||||
|
||||
--- Return wind direction as a string
|
||||
local function to_direction(degrees)
|
||||
-- Ref: https://www.campbellsci.eu/blog/convert-wind-directions
|
||||
if degrees == nil then return "Unknown dir" end
|
||||
local directions = {
|
||||
"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW",
|
||||
"WSW", "W", "WNW", "NW", "NNW", "N"
|
||||
}
|
||||
return directions[math.floor((degrees % 360) / 22.5) + 1]
|
||||
end
|
||||
|
||||
--- Convert degrees Celsius to Fahrenheit
|
||||
local function celsius_to_fahrenheit(c) return c * 9 / 5 + 32 end
|
||||
|
||||
-- Convert degrees Fahrenheit to Celsius
|
||||
local function fahrenheit_to_celsius(f) return (f - 32) * 5 / 9 end
|
||||
|
||||
local function gen_temperature_str(temp, fmt_str, show_other_units, units)
|
||||
local temp_str = string.format(fmt_str, temp)
|
||||
local s = temp_str .. '°' .. (units == 'metric' and 'C' or 'F')
|
||||
|
||||
if (show_other_units) then
|
||||
local temp_conv, units_conv
|
||||
if (units == 'metric') then
|
||||
temp_conv = celsius_to_fahrenheit(temp)
|
||||
units_conv = 'F'
|
||||
else
|
||||
temp_conv = fahrenheit_to_celsius(temp)
|
||||
units_conv = 'C'
|
||||
end
|
||||
|
||||
local temp_conv_str = string.format(fmt_str, temp_conv)
|
||||
s = s .. ' ' .. '(' .. temp_conv_str .. '°' .. units_conv .. ')'
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
local function uvi_index_color(uvi)
|
||||
local color
|
||||
if uvi >= 0 and uvi < 3 then color = '#A3BE8C'
|
||||
elseif uvi >= 3 and uvi < 6 then color = '#EBCB8B'
|
||||
elseif uvi >= 6 and uvi < 8 then color = '#D08770'
|
||||
elseif uvi >= 8 and uvi < 11 then color = '#BF616A'
|
||||
elseif uvi >= 11 then color = '#B48EAD'
|
||||
end
|
||||
|
||||
return '<span weight="bold" foreground="' .. color .. '">' .. uvi .. '</span>'
|
||||
end
|
||||
|
||||
local function worker(user_args)
|
||||
|
||||
local args = user_args or {}
|
||||
|
||||
--- Validate required parameters
|
||||
if args.coordinates == nil or args.api_key == nil then
|
||||
show_warning('Required parameters are not set: ' ..
|
||||
(args.coordinates == nil and '<b>coordinates</b>' or '') ..
|
||||
(args.api_key == nil and ', <b>api_key</b> ' or ''))
|
||||
return
|
||||
end
|
||||
|
||||
local coordinates = args.coordinates
|
||||
local api_key = args.api_key
|
||||
local font_name = args.font_name or beautiful.font:gsub("%s%d+$", "")
|
||||
local units = args.units or 'metric'
|
||||
local time_format_12h = args.time_format_12h
|
||||
local both_units_widget = args.both_units_widget or false
|
||||
local show_hourly_forecast = args.show_hourly_forecast
|
||||
local show_daily_forecast = args.show_daily_forecast
|
||||
local icon_pack_name = args.icons or 'weather-underground-icons'
|
||||
local icons_extension = args.icons_extension or '.png'
|
||||
local timeout = args.timeout or 120
|
||||
|
||||
local ICONS_DIR = WIDGET_DIR .. '/icons/' .. icon_pack_name .. '/'
|
||||
local owm_one_cal_api =
|
||||
('https://api.openweathermap.org/data/2.5/onecall' ..
|
||||
'?lat=' .. coordinates[1] .. '&lon=' .. coordinates[2] .. '&appid=' .. api_key ..
|
||||
'&units=' .. units .. '&exclude=minutely' ..
|
||||
(show_hourly_forecast == false and ',hourly' or '') ..
|
||||
(show_daily_forecast == false and ',daily' or ''))
|
||||
|
||||
weather_widget = wibox.widget {
|
||||
{
|
||||
{
|
||||
{
|
||||
{
|
||||
id = 'icon',
|
||||
resize = true,
|
||||
widget = wibox.widget.imagebox
|
||||
},
|
||||
valign = 'center',
|
||||
widget = wibox.container.place,
|
||||
},
|
||||
{
|
||||
id = 'txt',
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
layout = wibox.layout.fixed.horizontal,
|
||||
},
|
||||
margins = 4,
|
||||
layout = wibox.container.margin
|
||||
},
|
||||
shape = function(cr, width, height)
|
||||
gears.shape.rounded_rect(cr, width, height, 4)
|
||||
end,
|
||||
widget = wibox.container.background,
|
||||
set_image = function(self, path)
|
||||
self:get_children_by_id('icon')[1].image = path
|
||||
end,
|
||||
set_text = function(self, text)
|
||||
self:get_children_by_id('txt')[1].text = text
|
||||
end,
|
||||
is_ok = function(self, is_ok)
|
||||
if is_ok then
|
||||
self:get_children_by_id('icon')[1]:set_opacity(1)
|
||||
self:get_children_by_id('icon')[1]:emit_signal('widget:redraw_needed')
|
||||
else
|
||||
self:get_children_by_id('icon')[1]:set_opacity(0.2)
|
||||
self:get_children_by_id('icon')[1]:emit_signal('widget:redraw_needed')
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
local current_weather_widget = wibox.widget {
|
||||
{
|
||||
{
|
||||
{
|
||||
id = 'icon',
|
||||
resize = true,
|
||||
forced_width = 128,
|
||||
forced_height = 128,
|
||||
widget = wibox.widget.imagebox
|
||||
},
|
||||
align = 'center',
|
||||
widget = wibox.container.place
|
||||
},
|
||||
{
|
||||
id = 'description',
|
||||
font = font_name .. ' 10',
|
||||
align = 'center',
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
forced_width = 128,
|
||||
layout = wibox.layout.align.vertical
|
||||
},
|
||||
{
|
||||
{
|
||||
{
|
||||
id = 'temp',
|
||||
font = font_name .. ' 36',
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
{
|
||||
id = 'feels_like_temp',
|
||||
align = 'center',
|
||||
font = font_name .. ' 9',
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
layout = wibox.layout.fixed.vertical
|
||||
},
|
||||
{
|
||||
{
|
||||
id = 'wind',
|
||||
font = font_name .. ' 9',
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
{
|
||||
id = 'humidity',
|
||||
font = font_name .. ' 9',
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
{
|
||||
id = 'uv',
|
||||
font = font_name .. ' 9',
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
expand = 'inside',
|
||||
layout = wibox.layout.align.vertical
|
||||
},
|
||||
spacing = 16,
|
||||
forced_width = 150,
|
||||
layout = wibox.layout.fixed.vertical
|
||||
},
|
||||
forced_width = 300,
|
||||
layout = wibox.layout.flex.horizontal,
|
||||
update = function(self, weather)
|
||||
self:get_children_by_id('icon')[1]:set_image(
|
||||
ICONS_DIR .. icon_map[weather.weather[1].icon] .. icons_extension)
|
||||
self:get_children_by_id('temp')[1]:set_text(gen_temperature_str(weather.temp, '%.0f', false, units))
|
||||
self:get_children_by_id('feels_like_temp')[1]:set_text(
|
||||
'Feels like ' .. gen_temperature_str(weather.feels_like, '%.0f', false, units))
|
||||
self:get_children_by_id('description')[1]:set_text(weather.weather[1].description)
|
||||
self:get_children_by_id('wind')[1]:set_markup(
|
||||
'Wind: <b>' .. weather.wind_speed .. 'm/s (' .. to_direction(weather.wind_deg) .. ')</b>')
|
||||
self:get_children_by_id('humidity')[1]:set_markup('Humidity: <b>' .. weather.humidity .. '%</b>')
|
||||
self:get_children_by_id('uv')[1]:set_markup('UV: ' .. uvi_index_color(weather.uvi))
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
local daily_forecast_widget = {
|
||||
forced_width = 300,
|
||||
layout = wibox.layout.flex.horizontal,
|
||||
update = function(self, forecast, timezone_offset)
|
||||
local count = #self
|
||||
for i = 0, count do self[i]=nil end
|
||||
for i, day in ipairs(forecast) do
|
||||
if i > 5 then break end
|
||||
local day_forecast = wibox.widget {
|
||||
{
|
||||
text = os.date('%a', tonumber(day.dt) + tonumber(timezone_offset)),
|
||||
align = 'center',
|
||||
font = font_name .. ' 9',
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
{
|
||||
{
|
||||
{
|
||||
image = ICONS_DIR .. icon_map[day.weather[1].icon] .. icons_extension,
|
||||
resize = true,
|
||||
forced_width = 48,
|
||||
forced_height = 48,
|
||||
widget = wibox.widget.imagebox
|
||||
},
|
||||
align = 'center',
|
||||
layout = wibox.container.place
|
||||
},
|
||||
{
|
||||
text = day.weather[1].description,
|
||||
font = font_name .. ' 8',
|
||||
align = 'center',
|
||||
forced_height = 50,
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
layout = wibox.layout.fixed.vertical
|
||||
},
|
||||
{
|
||||
{
|
||||
text = gen_temperature_str(day.temp.day, '%.0f', false, units),
|
||||
align = 'center',
|
||||
font = font_name .. ' 9',
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
{
|
||||
text = gen_temperature_str(day.temp.night, '%.0f', false, units),
|
||||
align = 'center',
|
||||
font = font_name .. ' 9',
|
||||
widget = wibox.widget.textbox
|
||||
},
|
||||
layout = wibox.layout.fixed.vertical
|
||||
},
|
||||
spacing = 8,
|
||||
layout = wibox.layout.fixed.vertical
|
||||
}
|
||||
table.insert(self, day_forecast)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
local hourly_forecast_graph = wibox.widget {
|
||||
step_width = 12,
|
||||
color = '#EBCB8B',
|
||||
background_color = beautiful.bg_normal,
|
||||
forced_height = 100,
|
||||
forced_width = 300,
|
||||
widget = wibox.widget.graph,
|
||||
set_max_value = function(self, new_max_value)
|
||||
self.max_value = new_max_value
|
||||
end,
|
||||
set_min_value = function(self, new_min_value)
|
||||
self.min_value = new_min_value
|
||||
end
|
||||
}
|
||||
local hourly_forecast_negative_graph = wibox.widget {
|
||||
step_width = 12,
|
||||
color = '#5E81AC',
|
||||
background_color = beautiful.bg_normal,
|
||||
forced_height = 100,
|
||||
forced_width = 300,
|
||||
widget = wibox.widget.graph,
|
||||
set_max_value = function(self, new_max_value)
|
||||
self.max_value = new_max_value
|
||||
end,
|
||||
set_min_value = function(self, new_min_value)
|
||||
self.min_value = new_min_value
|
||||
end
|
||||
}
|
||||
|
||||
local hourly_forecast_widget = {
|
||||
layout = wibox.layout.fixed.vertical,
|
||||
update = function(self, hourly)
|
||||
local hours_below = {
|
||||
id = 'hours',
|
||||
forced_width = 300,
|
||||
layout = wibox.layout.flex.horizontal
|
||||
}
|
||||
local temp_below = {
|
||||
id = 'temp',
|
||||
forced_width = 300,
|
||||
layout = wibox.layout.flex.horizontal
|
||||
}
|
||||
|
||||
local max_temp = -1000
|
||||
local min_temp = 1000
|
||||
local values = {}
|
||||
for i, hour in ipairs(hourly) do
|
||||
if i > 25 then break end
|
||||
values[i] = hour.temp
|
||||
if max_temp < hour.temp then max_temp = hour.temp end
|
||||
if min_temp > hour.temp then min_temp = hour.temp end
|
||||
if (i - 1) % 5 == 0 then
|
||||
table.insert(hours_below, wibox.widget {
|
||||
text = os.date(time_format_12h and '%I%p' or '%H:00', tonumber(hour.dt)),
|
||||
align = 'center',
|
||||
font = font_name .. ' 9',
|
||||
widget = wibox.widget.textbox
|
||||
})
|
||||
table.insert(temp_below, wibox.widget {
|
||||
markup = '<span foreground="'
|
||||
.. (tonumber(hour.temp) > 0 and '#2E3440' or '#ECEFF4') .. '">'
|
||||
.. string.format('%.0f', hour.temp) .. '°' .. '</span>',
|
||||
align = 'center',
|
||||
font = font_name .. ' 9',
|
||||
widget = wibox.widget.textbox
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
hourly_forecast_graph:set_max_value(math.max(max_temp, math.abs(min_temp)))
|
||||
hourly_forecast_graph:set_min_value(min_temp > 0 and min_temp * 0.7 or 0) -- move graph a bit up
|
||||
|
||||
hourly_forecast_negative_graph:set_max_value(math.abs(min_temp))
|
||||
hourly_forecast_negative_graph:set_min_value(max_temp < 0 and math.abs(max_temp) * 0.7 or 0)
|
||||
|
||||
for _, value in ipairs(values) do
|
||||
if value >= 0 then
|
||||
hourly_forecast_graph:add_value(value)
|
||||
hourly_forecast_negative_graph:add_value(0)
|
||||
else
|
||||
hourly_forecast_graph:add_value(0)
|
||||
hourly_forecast_negative_graph:add_value(math.abs(value))
|
||||
end
|
||||
end
|
||||
|
||||
local count = #self
|
||||
for i = 0, count do self[i]=nil end
|
||||
|
||||
-- all temperatures are positive
|
||||
if min_temp > 0 then
|
||||
table.insert(self, wibox.widget{
|
||||
{
|
||||
hourly_forecast_graph,
|
||||
reflection = {horizontal = true},
|
||||
widget = wibox.container.mirror
|
||||
},
|
||||
{
|
||||
temp_below,
|
||||
valign = 'bottom',
|
||||
widget = wibox.container.place
|
||||
},
|
||||
id = 'graph',
|
||||
layout = wibox.layout.stack
|
||||
})
|
||||
table.insert(self, hours_below)
|
||||
|
||||
-- all temperatures are negative
|
||||
elseif max_temp < 0 then
|
||||
table.insert(self, hours_below)
|
||||
table.insert(self, wibox.widget{
|
||||
{
|
||||
hourly_forecast_negative_graph,
|
||||
reflection = {horizontal = true, vertical = true},
|
||||
widget = wibox.container.mirror
|
||||
},
|
||||
{
|
||||
temp_below,
|
||||
valign = 'top',
|
||||
widget = wibox.container.place
|
||||
},
|
||||
id = 'graph',
|
||||
layout = wibox.layout.stack
|
||||
})
|
||||
|
||||
-- there are both negative and positive temperatures
|
||||
else
|
||||
table.insert(self, wibox.widget{
|
||||
{
|
||||
hourly_forecast_graph,
|
||||
reflection = {horizontal = true},
|
||||
widget = wibox.container.mirror
|
||||
},
|
||||
{
|
||||
temp_below,
|
||||
valign = 'bottom',
|
||||
widget = wibox.container.place
|
||||
},
|
||||
id = 'graph',
|
||||
layout = wibox.layout.stack
|
||||
})
|
||||
table.insert(self, wibox.widget{
|
||||
{
|
||||
hourly_forecast_negative_graph,
|
||||
reflection = {horizontal = true, vertical = true},
|
||||
widget = wibox.container.mirror
|
||||
},
|
||||
{
|
||||
hours_below,
|
||||
valign = 'top',
|
||||
widget = wibox.container.place
|
||||
},
|
||||
id = 'graph',
|
||||
layout = wibox.layout.stack
|
||||
})
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
local function update_widget(widget, stdout, stderr)
|
||||
if stderr ~= '' then
|
||||
if not warning_shown then
|
||||
if (stderr ~= 'curl: (52) Empty reply from server'
|
||||
and stderr ~= 'curl: (28) Failed to connect to api.openweathermap.org port 443: Connection timed out'
|
||||
and stderr:find('^curl: %(18%) transfer closed with %d+ bytes remaining to read$') ~= nil
|
||||
) then
|
||||
show_warning(stderr)
|
||||
end
|
||||
warning_shown = true
|
||||
widget:is_ok(false)
|
||||
tooltip:add_to_object(widget)
|
||||
|
||||
widget:connect_signal('mouse::enter', function() tooltip.text = stderr end)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
warning_shown = false
|
||||
tooltip:remove_from_object(widget)
|
||||
widget:is_ok(true)
|
||||
|
||||
local result = json.decode(stdout)
|
||||
|
||||
widget:set_image(ICONS_DIR .. icon_map[result.current.weather[1].icon] .. icons_extension)
|
||||
widget:set_text(gen_temperature_str(result.current.temp, '%.0f', both_units_widget, units))
|
||||
|
||||
current_weather_widget:update(result.current)
|
||||
|
||||
local final_widget = {
|
||||
current_weather_widget,
|
||||
spacing = 16,
|
||||
layout = wibox.layout.fixed.vertical
|
||||
}
|
||||
|
||||
if show_hourly_forecast then
|
||||
hourly_forecast_widget:update(result.hourly)
|
||||
table.insert(final_widget, hourly_forecast_widget)
|
||||
end
|
||||
|
||||
if show_daily_forecast then
|
||||
daily_forecast_widget:update(result.daily, result.timezone_offset)
|
||||
table.insert(final_widget, daily_forecast_widget)
|
||||
end
|
||||
|
||||
weather_popup:setup({
|
||||
{
|
||||
final_widget,
|
||||
margins = 10,
|
||||
widget = wibox.container.margin
|
||||
},
|
||||
bg = beautiful.bg_normal,
|
||||
widget = wibox.container.background
|
||||
})
|
||||
end
|
||||
|
||||
weather_widget:buttons(gears.table.join(awful.button({}, 1, function()
|
||||
if weather_popup.visible then
|
||||
weather_widget:set_bg('#00000000')
|
||||
weather_popup.visible = not weather_popup.visible
|
||||
else
|
||||
weather_widget:set_bg(beautiful.bg_focus)
|
||||
weather_popup:move_next_to(mouse.current_widget_geometry)
|
||||
end
|
||||
end)))
|
||||
|
||||
watch(
|
||||
string.format(GET_FORECAST_CMD, owm_one_cal_api),
|
||||
timeout, -- API limit is 1k req/day; day has 1440 min; every 2 min is good
|
||||
update_widget, weather_widget
|
||||
)
|
||||
|
||||
return weather_widget
|
||||
end
|
||||
|
||||
return setmetatable(weather_widget, {__call = function(_, ...) return worker(...) end})
|