diff --git a/awesome/src/assets/icons/calendar/add_ical.svg b/awesome/src/assets/icons/calendar/add_ical.svg
new file mode 100644
index 0000000..80a6f75
--- /dev/null
+++ b/awesome/src/assets/icons/calendar/add_ical.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/src/assets/icons/calendar/add_task.svg b/awesome/src/assets/icons/calendar/add_task.svg
new file mode 100644
index 0000000..bb280a8
--- /dev/null
+++ b/awesome/src/assets/icons/calendar/add_task.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/src/assets/icons/calendar/calendar.svg b/awesome/src/assets/icons/calendar/calendar.svg
new file mode 100644
index 0000000..6d5006c
--- /dev/null
+++ b/awesome/src/assets/icons/calendar/calendar.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/awesome/src/assets/icons/calendar/chevron-left.svg b/awesome/src/assets/icons/calendar/chevron-left.svg
new file mode 100644
index 0000000..53831bc
--- /dev/null
+++ b/awesome/src/assets/icons/calendar/chevron-left.svg
@@ -0,0 +1,3 @@
+
diff --git a/awesome/src/assets/icons/calendar/chevron-right.svg b/awesome/src/assets/icons/calendar/chevron-right.svg
new file mode 100644
index 0000000..b2da475
--- /dev/null
+++ b/awesome/src/assets/icons/calendar/chevron-right.svg
@@ -0,0 +1,3 @@
+
diff --git a/awesome/src/assets/userpfp/crylia.png b/awesome/src/assets/userpfp/crylia.png
index 44f69c6..671fbe2 100644
Binary files a/awesome/src/assets/userpfp/crylia.png and b/awesome/src/assets/userpfp/crylia.png differ
diff --git a/awesome/src/bindings/global_keys.lua b/awesome/src/bindings/global_keys.lua
index 2e12be0..40e30dc 100644
--- a/awesome/src/bindings/global_keys.lua
+++ b/awesome/src/bindings/global_keys.lua
@@ -235,7 +235,7 @@ return gears.table.join(
awful.key(
{},
"XF86AudioMute",
- function()
+ function(c)
awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle")
awesome.emit_signal("widget::volume_osd:rerun")
end,
@@ -244,11 +244,11 @@ return gears.table.join(
awful.key(
{},
"XF86MonBrightnessUp",
- function()
+ function(c)
awful.spawn.easy_async_with_shell(
- "xfpm-power-backlight-helper --get-brightness",
+ "pkexec xfpm-power-backlight-helper --get-brightness",
function(stdout)
- awful.spawn(awful.util.getdir("config") .. "src/scripts/backlight.sh set " ..
+ awful.spawn("pkexec xfpm-power-backlight-helper --set-brightness " ..
tostring(tonumber(stdout) + BACKLIGHT_SEPS))
awesome.emit_signal("brightness::update")
end
@@ -259,11 +259,12 @@ return gears.table.join(
awful.key(
{},
"XF86MonBrightnessDown",
- function()
+ function(c)
awful.spawn.easy_async_with_shell(
- "xfpm-power-backlight-helper --get-brightness",
+ "pkexec xfpm-power-backlight-helper --get-brightness",
function(stdout)
- awful.spawn(awful.util.getdir("config") .. "src/scripts/backlight.sh set " ..
+ awful.spawn(
+ "pkexec xfpm-power-backlight-helper --set-brightness " ..
tostring(tonumber(stdout) - BACKLIGHT_SEPS))
awesome.emit_signal("brightness::update")
end
diff --git a/awesome/src/core/rules.lua b/awesome/src/core/rules.lua
index 36403c0..84c7f8d 100644
--- a/awesome/src/core/rules.lua
+++ b/awesome/src/core/rules.lua
@@ -38,18 +38,25 @@ awful.rules.rules = {
titlebars_enabled = true
}
},
- rule_any = {
- class = {
- 'Wine',
- 'dolphin-emu',
- 'Steam',
- 'Citra',
+ {
+ id = "games",
+ rule_any = {
+ class = {
+ "steam_app_.%d+",
+ "gta5.exe",
+ },
},
- name = { 'Steam' }
- },
- properties = {
- skip_decoration = true,
- placement = awful.placement.centered
+ properties = {
+ tag = "9",
+ switchtotag = true,
+ fullscreen = true,
+ screen = screen[1],
+ floating = true,
+ },
+ focus = true,
+ callback = function(c)
+ awful.screen.focused()
+ end
}
}
diff --git a/awesome/src/core/signals.lua b/awesome/src/core/signals.lua
index a45c2ec..02c19f3 100644
--- a/awesome/src/core/signals.lua
+++ b/awesome/src/core/signals.lua
@@ -95,9 +95,6 @@ tag.connect_signal(
---@param icon_override_hover string | nil the hover effect color
function Hover_signal(widget, bg_override, fg_override, border_override, icon_override, icon_override_hover)
local old_wibox, old_cursor, old_bg, old_fg, old_border
-
- local r, g, b
-
widget.bg = widget.bg or "#000000"
widget.fg = widget.fg or "#000000"
widget.border_color = widget.border_color or "#000000"
@@ -107,62 +104,72 @@ function Hover_signal(widget, bg_override, fg_override, border_override, icon_ov
widget.icon = widget:get_children_by_id("icon")[1]
end
- --[[ local r_timed_bg = rubato.timed { duration = 0.5 }
- local g_timed_bg = rubato.timed { duration = 0.5 }
- local b_timed_bg = rubato.timed { duration = 0.5 }
+ local _, rb, gb, bb = widget.bg:get_rgba()
+ local _, rf, gf, bf = widget.fg:get_rgba()
+ local rbo, gbo, bbo = color.utils.hex_to_rgba(widget.border_color)
+
+ local r_timed_bg = rubato.timed { duration = 0.3, pos = math.floor(rb * 255) }
+ local g_timed_bg = rubato.timed { duration = 0.3, pos = math.floor(gb * 255) }
+ local b_timed_bg = rubato.timed { duration = 0.3, pos = math.floor(bb * 255) }
+
+ local r_timed_fg = rubato.timed { duration = 0.3, pos = math.floor(rf * 255) }
+ local g_timed_fg = rubato.timed { duration = 0.3, pos = math.floor(gf * 255) }
+ local b_timed_fg = rubato.timed { duration = 0.3, pos = math.floor(bf * 255) }
+
+ local r_timed_border = rubato.timed { duration = 0.3, pos = math.floor(rbo) }
+ local g_timed_border = rubato.timed { duration = 0.3, pos = math.floor(gbo) }
+ local b_timed_border = rubato.timed { duration = 0.3, pos = math.floor(bbo) }
local function update_bg()
widget:set_bg("#" .. color.utils.rgba_to_hex { r_timed_bg.pos, g_timed_bg.pos, b_timed_bg.pos })
end
+ local function update_fg()
+ widget:set_fg("#" .. color.utils.rgba_to_hex { r_timed_fg.pos, g_timed_fg.pos, b_timed_fg.pos })
+ end
+
+ local function update_border()
+ widget:set_border_color("#" .. color.utils.rgba_to_hex { r_timed_border.pos, g_timed_border.pos, b_timed_border.pos })
+ end
+
r_timed_bg:subscribe(update_bg)
g_timed_bg:subscribe(update_bg)
b_timed_bg:subscribe(update_bg)
+ r_timed_fg:subscribe(update_fg)
+ g_timed_fg:subscribe(update_fg)
+ b_timed_fg:subscribe(update_fg)
+
+ r_timed_border:subscribe(update_border)
+ g_timed_border:subscribe(update_border)
+ b_timed_border:subscribe(update_border)
+
local function set_bg(newbg)
- r_timed_bg.target, g_timed_bg.target, b_timed_bg.target = color.utils.hex_to_rgba(newbg)
- end ]]
-
- local mouse_enter = function()
- _, r, g, b, _ = widget.bg:get_rgba()
- old_bg = RGB_to_hex(r, g, b)
- if bg_override or old_bg then
- widget:set_bg(bg_override or old_bg .. "dd")
- end
- _, r, g, b, _ = widget.fg:get_rgba()
- old_fg = RGB_to_hex(r, g, b)
- if fg_override or old_fg then
- widget:set_fg(fg_override or old_fg .. "dd")
- end
- old_border = widget.border_color
- if border_override or old_border then
- widget.border_color = border_override or old_border .. "dd"
- end
- if icon and widget.icon and icon_override and icon_override_hover then
- widget.icon.image = gears.color.recolor_image(icon, icon_override_hover)
- end
- local w = mouse.current_wibox
- if w then
- old_cursor, old_wibox = w.cursor, w
- w.cursor = "hand1"
- end
+ r_timed_bg.target, g_timed_bg.target, b_timed_bg.target = newbg[1], newbg[2], newbg[3]
end
- --[[ local button_press = function()
- if old_bg or bg_override then
- if bg_override then
- bg_override = bg_override .. "bb"
- end
- widget.bg = bg_override or old_bg .. "bb"
- end
- if fg_override or old_fg then
- if fg_override then
- fg_override = fg_override .. "bb"
- end
- widget.fg = fg_override or old_fg .. "bb"
- end
+ local function set_fg(newfg)
+ r_timed_fg.target, g_timed_fg.target, b_timed_fg.target = newfg[1], newfg[2], newfg[3]
end
+ local function set_border(newborder)
+ r_timed_border.target, g_timed_border.target, b_timed_border.target = newborder[1], newborder[2], newborder[3]
+ end
+
+ local _, rbg, gbg, bbg, abg = widget.bg:get_rgba()
+ old_bg = RGB_to_hex(rbg, gbg, bbg)
+ local _, rfg, gfg, bfg, afg = widget.fg:get_rgba()
+ old_fg = RGB_to_hex(rfg, gfg, bfg)
+ old_border = widget.border_color
+ local rborder, gborder, bborder = color.utils.hex_to_rgba(old_border)
+
+ local function match_hex(hex1, hex2)
+ local r1, g1, b1 = color.utils.hex_to_rgba(hex1)
+ local r2, g2, b2 = color.utils.hex_to_rgba(hex2)
+ return math.abs(r1 - r2) <= 100 and math.abs(g1 - g2) <= 100 and math.abs(b1 - b2) <= 100
+ end
+
+ --[[
local button_release = function()
if old_bg or bg_override then
if bg_override then
@@ -179,14 +186,18 @@ function Hover_signal(widget, bg_override, fg_override, border_override, icon_ov
end ]]
local mouse_leave = function()
+
if old_bg then
- widget:set_bg(old_bg)
+ local r, g, b = color.utils.hex_to_rgba(old_bg)
+ set_bg({ r, g, b })
end
if old_fg then
- widget:set_fg(old_fg)
+ local r, g, b = color.utils.hex_to_rgba(old_fg)
+ set_fg({ r, g, b })
end
if old_border then
- widget.border_color = old_border
+ local r, g, b = color.utils.hex_to_rgba(old_border)
+ set_border({ r, g, b })
end
if old_wibox then
old_wibox.cursor = old_cursor
@@ -197,8 +208,76 @@ function Hover_signal(widget, bg_override, fg_override, border_override, icon_ov
end
end
+ local mouse_enter = function()
+ _, rbg, gbg, bbg, abg = widget.bg:get_rgba()
+ if not match_hex(RGB_to_hex(rbg, gbg, bbg), old_bg) then
+ old_bg = RGB_to_hex(rbg, gbg, bbg)
+ set_bg({ rbg * 0.9 * 255, gbg * 0.9 * 255, bbg * 0.9 * 255 })
+ end
+ if old_bg then
+ if bg_override then
+ rbg, gbg, bbg = color.utils.hex_to_rgba(bg_override)
+ set_bg({ rbg, gbg, bbg })
+ else
+ set_bg({ rbg * 0.9 * 255, gbg * 0.9 * 255, bbg * 0.9 * 255 })
+ end
+ end
+
+ _, rfg, gfg, bfg, afg = widget.fg:get_rgba()
+ if not match_hex(RGB_to_hex(rfg, gfg, bfg), old_fg) then
+ old_fg = RGB_to_hex(rfg, gfg, bfg)
+ set_fg({ rfg * 0.9 * 255, gfg * 0.9 * 255, bfg * 0.9 * 255 })
+ end
+ if fg_override or old_fg then
+ if fg_override then
+ rfg, gfg, bfg = color.utils.hex_to_rgba(fg_override)
+ set_fg({ rfg, gfg, bfg })
+ else
+ set_fg({ rfg * 0.9 * 255, gfg * 0.9 * 255, bfg * 0.9 * 255 })
+ end
+ end
+
+ if not match_hex(old_border, widget.border_color) then
+ old_border = widget.border_color
+ rborder, gborder, bborder = color.utils.hex_to_rgba(old_border)
+ end
+ if border_override or old_border then
+ if border_override then
+ rborder, gborder, bborder = color.utils.hex_to_rgba(border_override)
+ set_border({ rborder, gborder, bborder })
+ else
+ set_border({ rborder * 0.9, gborder * 0.9, bborder * 0.9 })
+ end
+ end
+ if icon and widget.icon and icon_override and icon_override_hover then
+ widget.icon.image = gears.color.recolor_image(icon, icon_override_hover)
+ end
+ local w = mouse.current_wibox
+ if w then
+ old_cursor, old_wibox = w.cursor, w
+ w.cursor = "hand1"
+ end
+ --widget:connect_signal("mouse::leave", mouse_leave)
+ end
+
+ local button_press = function()
+ --[[ if old_bg or bg_override then
+ if bg_override then
+ bg_override = bg_override .. "bb"
+ end
+ widget.bg = bg_override or old_bg .. "bb"
+ end
+ if fg_override or old_fg then
+ if fg_override then
+ fg_override = fg_override .. "bb"
+ end
+ widget.fg = fg_override or old_fg .. "bb"
+ end ]]
+ --widget:disconnect_signal("mouse::leave", mouse_leave)
+ end
+
widget:connect_signal("mouse::enter", mouse_enter)
- --widget:connect_signal("button::press", button_press)
+ widget:connect_signal("button::press", button_press)
--widget:connect_signal("button::release", button_release)
widget:connect_signal("mouse::leave", mouse_leave)
end
diff --git a/awesome/src/lib/overflow_widget/overflow.lua b/awesome/src/lib/overflow_widget/overflow.lua
index 7e36a5d..69d55f4 100644
--- a/awesome/src/lib/overflow_widget/overflow.lua
+++ b/awesome/src/lib/overflow_widget/overflow.lua
@@ -18,6 +18,8 @@ local gshape = require('gears.shape')
local gobject = require('gears.object')
local mousegrabber = mousegrabber
+local rubato = require("src.lib.rubato")
+
local overflow = { mt = {} }
-- Determine the required space to draw the layout's children and, if necessary,
@@ -305,6 +307,9 @@ end
-- @tparam number scroll_factor The scroll factor.
-- @propemits true false
+overflow.rubato_timed = rubato.timed { duration = 0.2 }
+
+local first_call = true
function overflow:set_scroll_factor(factor)
local current = self._private.scroll_factor
local interval = self._private.used_in_dir - self._private.avail_in_dir
@@ -318,10 +323,22 @@ function overflow:set_scroll_factor(factor)
return
end
- self._private.scroll_factor = math.min(1, math.max(factor, 0))
- self:emit_signal("widget::layout_changed")
- self:emit_signal("property::scroll_factor", factor)
+ local function update_scroll()
+ self._private.scroll_factor = overflow.rubato_timed.pos
+ self:emit_signal("widget::layout_changed")
+ self:emit_signal("property::scroll_factor", factor)
+ end
+
+ -- Make sure it only subscribes once
+ if first_call then
+ overflow.rubato_timed:subscribe(update_scroll)
+ --first_call = false
+ end
+
+ -- Set the target to the new target + remaining target from last scroll. This makes it scroll faster and correctly.
+ overflow.rubato_timed.target = math.min(1,
+ math.max(factor + (overflow.rubato_timed.target - overflow.rubato_timed.pos), 0))
end
function overflow:get_scroll_factor()
diff --git a/awesome/src/lib/rubato b/awesome/src/lib/rubato
index d486ee3..b40ecae 160000
--- a/awesome/src/lib/rubato
+++ b/awesome/src/lib/rubato
@@ -1 +1 @@
-Subproject commit d486ee33a8b96ba76a4d948e341c7e89ba0554a5
+Subproject commit b40ecae70b01b9917df2ba192f058f5e0b768798
diff --git a/awesome/src/modules/application_launcher/init.lua b/awesome/src/modules/application_launcher/init.lua
index a64bb0f..7b8cc10 100644
--- a/awesome/src/modules/application_launcher/init.lua
+++ b/awesome/src/modules/application_launcher/init.lua
@@ -22,7 +22,7 @@ return function(s)
spacing = dpi(10),
layout = require("src.lib.overflow_widget.overflow").vertical,
scrollbar_width = 0,
- step = dpi(50),
+ step = dpi(100),
id = "scroll_bar",
},
spacing = dpi(10),
diff --git a/awesome/src/modules/calendar/calendar.lua b/awesome/src/modules/calendar/calendar.lua
new file mode 100644
index 0000000..5cfb5a1
--- /dev/null
+++ b/awesome/src/modules/calendar/calendar.lua
@@ -0,0 +1,1085 @@
+--------------------------------------
+-- This is the application launcher --
+--------------------------------------
+
+-- Awesome Libs
+local awful = require("awful")
+local dpi = require("beautiful").xresources.apply_dpi
+local gears = require("gears")
+local wibox = require("wibox")
+local ical_parser = require("src.tools.ical_parser")
+
+local icondir = awful.util.getdir("config") .. "src/assets/icons/calendar/"
+
+--- Month name lookup table
+local months_table = {
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+ "January",
+ "February",
+}
+
+--- Table to easily shift back every month by two months
+local month_convert = {
+ 11,
+ 12,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+}
+
+--- Weekdays name lookup table
+local weekdays_table = {
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat",
+ "Sun",
+}
+
+--- Create a date object from the current date
+local os_date = os.date("%d%m%Y")
+local date = {
+ day = math.floor(os_date:sub(1, 2)),
+ month = month_convert[math.floor(os_date:sub(3, 4))],
+ year = math.floor(os_date:sub(5, 8))
+}
+
+---Calculates the weekday of a given date
+---@param day number|string? as number, usually from date.da
+---@param month number|string? as number, usually from date.month
+---@param year number|string? as number, usually from date.year
+---@return number|nil weekday as number
+local function get_date_weekday(day, month, year)
+ if not (day and month and year) then return end
+
+ if (month == 11) or (month == 12) then
+ year = year - 1
+ end
+
+ -- No idea how the algorithm works, but since it works -> don't touch it!
+ local w = ((day + math.floor(2.6 * month - 0.2) - 2 * tonumber(tostring(year):match("([0-9]+)[0-9][0-9]")) +
+ tonumber(tostring(year):match("[0-9][0-9]([0-9]+)")) +
+ math.floor(tonumber(tostring(year):match("[0-9][0-9]([0-9]+)")) / 4) +
+ math.floor(tonumber(tostring(year):match("([0-9]+)[0-9][0-9]")) / 4)) % 7)
+ --TODO: Add user variable to choose between Sunday and Monday weekstart
+ if w == 0 then w = 7 end
+ return w
+end
+
+---Returns the length of the month from a lookup table and also check for leap years
+---@param month number? as number, usually from date.month, can also be a string
+---@param year number? as number, usually from date.year, can also be a string
+---@return integer|nil month_length as integer
+local function get_last_day_of_month(month, year)
+ if not (month and year) then return end
+
+ month = tonumber(month)
+ local last_day = {
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ 31,
+ 28,
+ }
+ --In this calculcation February is the 12th of last year
+ if (month == 12) and (math.floor(year % 4) == 0) then
+ return 29
+ else
+ return last_day[month]
+ end
+end
+
+---Simple function to calculate how many weeks will need to be displayed in a calendar
+---@param month number? as number, usually from date.month, can also be a string
+---@param year number? as number, usually from date.year, can also be a string
+---@return number|nil weeks ammount of weeks between 4-6
+local function get_weeks_in_month(month, year)
+ if not (month and year) then return end
+ return math.ceil((get_last_day_of_month(month, year) + get_date_weekday(1, month, year) - 1) / 7)
+end
+
+---Gets the last month and accounts for year changes
+---@param d date date object
+---@return table|nil date returns a date object
+local function get_last_month(d)
+ if not (d) then return end
+ if d.month == 1 then
+ return { month = 12, year = d.year - 1 }
+ else
+ return { month = d.month - 1, year = d.year }
+ end
+end
+
+---Simple function to create a widget 7x for each day of the week
+---@return table weeks_widget All weekdays names as a widget
+local function create_weekdays()
+ local weekdays = { layout = wibox.layout.flex.horizontal }
+ for i = 1, 7 do
+ table.insert(weekdays, wibox.widget {
+ {
+ text = weekdays_table[i],
+ align = "center",
+ valign = "center",
+ widget = wibox.widget.textbox,
+ },
+ bg = Theme_config.calendar.weekdays.bg,
+ fg = Theme_config.calendar.weekdays.fg,
+ widget = wibox.container.background,
+ })
+ end
+ return weekdays
+end
+
+---Create tasks from ical object
+---@return table|nil tasks All tasks as a table
+local function create_tasks()
+ if not ical_parser or not ical_parser.VCALENDAR then return end
+ local tasks = {}
+ --TODO: Initialize the timezone from ical.VCALENDAR.VTIMEZONE and make sure the time is correct
+
+ -- Sort every VEVENT in ical by date into the tasks table.
+ for _, calendar in ipairs(ical_parser.VCALENDAR) do
+ for _, event in ipairs(calendar.VEVENT) do
+ local start_time = event.DTSTART.DTSTART
+ start_time.month = month_convert[start_time.month]
+ local end_time
+ if event.DTEND then
+ end_time = event.DTEND.DTEND
+ end_time.month = month_convert[end_time.month]
+ end
+
+ if event.RRULE then
+ if event.RRULE.FREQ == "DAILY" then
+ elseif event.RRULE.FREQ == "WEEKLY" then
+ -- An event will always start on the day it first occurs.
+ local event_start = start_time
+ local event_end = event.RRULE.UNTIL
+
+ local year_counter = event_start.year
+ local month_counter = event_start.month
+ if month_counter == 11 then
+ year_counter = year_counter - 1
+ elseif month_counter == 12 then
+ year_counter = year_counter - 1
+ end
+ local day_counter = event_start.day
+ local task = {}
+ while (year_counter <= event_end.year) or (month_counter <= event_end.month) or (day_counter <= event_end.day) do
+ -- First event will always be right since we start on its starting day
+ task = {
+ date_start = {
+ year = year_counter,
+ month = month_counter,
+ day = day_counter,
+ hour = event_start.hour or 0,
+ minute = event_start.minute or 0,
+ second = event_start.second or 0
+ },
+ date_end = {
+ year = year_counter,
+ month = month_counter,
+ day = day_counter,
+ hour = end_time.hour or 0,
+ minute = end_time.minute or 0,
+ second = end_time.second or 0
+ },
+ summary = event.SUMMARY,
+ location = event.LOCATION,
+ }
+
+ if event.VALARM then
+ task.alarm = {
+ time = event.VALARM.TRIGGER.TRIGGER
+ }
+ local alarm_time = task.alarm.time:match("([-]?%d+)")
+ local alarm_unit = task.alarm.time:match("(%a)")
+ if alarm_unit == "W" then
+ alarm_time = alarm_time * 604800
+ elseif alarm_unit == "D" then
+ alarm_time = alarm_time * 86400
+ elseif alarm_unit == "H" then
+ alarm_time = alarm_time * 3600
+ elseif alarm_unit == "M" then
+ alarm_time = alarm_time * 60
+ end
+
+ --[[ gears.timer {
+ autostart = true,
+ callback = function()
+ if alarm_time then
+ require("naughty").notification {
+ app_name = "Task Alarm",
+ title = task.summary,
+ message = task.description,
+ urgency = "normal",
+ timeout = 5,
+ icon = icondir .. "/alarm.png",
+ }
+ gears.timer:stop()
+ end
+ end
+ } ]]
+ end
+
+ table.insert(tasks, task)
+
+ day_counter = day_counter + 7
+ local month_length = get_last_day_of_month(month_counter, year_counter)
+ if day_counter > month_length then
+ day_counter = day_counter - month_length
+ month_counter = month_counter + 1
+ end
+ if month_counter == 11 then
+ year_counter = year_counter + 1
+ end
+ if month_counter > 13 then
+ month_counter = 1
+ end
+ end
+ elseif event.RRULE.FREQ == "MONTHLY" then
+ elseif event.RRULE.FREQ == "YEARLY" then
+ if not end_time then
+ end_time = {
+ year = start_time.year + 1000,
+ }
+ end
+
+ local task = {}
+ for i = start_time.year, end_time.year, 1 do
+ task = {
+ date_start = {
+ year = i,
+ month = start_time.month,
+ day = start_time.day,
+ hour = start_time.hour or 0,
+ minute = start_time.minute or 0,
+ second = start_time.second or 0
+ },
+ date_end = {
+ year = i,
+ month = start_time.month,
+ day = start_time.day,
+ hour = end_time.hour or 0,
+ minute = end_time.minute or 0,
+ second = end_time.second or 0
+ },
+ summary = event.SUMMARY,
+ location = event.LOCATION,
+ description = event.DESCRIPTION,
+ url = event.URL,
+ }
+
+ if event.VALARM then
+ task.alarm = {
+ time = event.VALARM.TRIGGER.TRIGGER
+ }
+ local alarm_time = task.alarm.time:match("([-]?%d+)")
+ local alarm_unit = task.alarm.time:match("(%a)")
+ if alarm_unit == "W" then
+ alarm_time = alarm_time * 604800
+ elseif alarm_unit == "D" then
+ alarm_time = alarm_time * 86400
+ elseif alarm_unit == "H" then
+ alarm_time = alarm_time * 3600
+ elseif alarm_unit == "M" then
+ alarm_time = alarm_time * 60
+ end
+
+ --[[ gears.timer {
+ timeout = os.time(task.date_start) - os.time() + alarm_time,
+ autostart = true,
+ callback = function()
+ require("naughty").notification {
+ app_name = "Task Alarm",
+ title = task.summary,
+ message = task.description,
+ urgency = "normal",
+ timeout = 5,
+ icon = icondir .. "/alarm.png",
+ }
+ end
+ } ]]
+ end
+
+ table.insert(tasks, task)
+ end
+ end
+ else
+ local task = {
+ date_start = {
+ year = start_time.year,
+ month = start_time.month,
+ day = start_time.day,
+ hour = start_time.hour or 0,
+ minute = start_time.minute or 0,
+ second = start_time.second or 0
+ },
+ date_end = {
+ year = start_time.year,
+ month = start_time.month,
+ day = start_time.day,
+ hour = start_time.hour or 0,
+ minute = start_time.minute or 0,
+ second = start_time.second or 0
+ },
+ summary = event.SUMMARY,
+ location = event.LOCATION,
+ description = event.DESCRIPTION,
+ url = event.URL,
+ }
+
+ if event.VALARM then
+ task.alarm = {
+ time = event.VALARM.TRIGGER.TRIGGER
+ }
+ local alarm_time = task.alarm.time:match("([-]?%d+)")
+ local alarm_unit = task.alarm.time:match("(%a)")
+ if alarm_unit == "W" then
+ alarm_time = alarm_time * 604800
+ elseif alarm_unit == "D" then
+ alarm_time = alarm_time * 86400
+ elseif alarm_unit == "H" then
+ alarm_time = alarm_time * 3600
+ elseif alarm_unit == "M" then
+ alarm_time = alarm_time * 60
+ end
+
+ --[[ gears.timer {
+ timeout = os.time(task.date_start) - os.time() + alarm_time,
+ autostart = true,
+ callback = function()
+ require("naughty").notification {
+ app_name = "Task Alarm",
+ title = task.summary,
+ message = task.description,
+ urgency = "normal",
+ timeout = 5,
+ icon = icondir .. "/alarm.png",
+ }
+ end
+ } ]]
+ end
+ table.insert(tasks, task)
+ end
+ end
+ end
+
+
+ return tasks
+end
+
+local tasks = create_tasks()
+
+local selected_day = {
+ year = date.year,
+ month = date.month,
+ day = date.day,
+ col = 1,
+ row = 1,
+}
+
+return function(s)
+ -- The calendar grid
+ local calendar_matrix = wibox.widget { layout = wibox.layout.grid }
+
+ local weeks = wibox.widget { layout = wibox.layout.fixed.vertical }
+
+ ---Main function to create the calendar widget
+ ---Probably needs some refractor at some point since it's a bit messy
+ ---@return widget calendar_widget
+ local function create_calendar()
+
+ calendar_matrix:reset()
+
+ --- Months table holds every month with their starting week day, length(30/31 or 28/29), the last week day and the name
+ local months = {}
+ for m_num, month in ipairs(months_table) do
+ months[m_num] = {
+ name = month,
+ first_day = get_date_weekday("01", m_num, date.year),
+ length = get_last_day_of_month(m_num, date.year),
+ last_day = get_date_weekday(get_last_day_of_month(m_num, date.year), m_num, date.year),
+ weeks = get_weeks_in_month(m_num, date.year)
+ }
+ end
+
+ local function get_tasks_for_day(day, month, year)
+ if not tasks or #tasks == 0 then return end
+ local tasks_layout = {
+ layout = require("src.lib.overflow_widget.overflow").vertical,
+ scrollbar_width = 0,
+ step = dpi(50),
+ spacing = dpi(2)
+ }
+ for _, task in ipairs(tasks) do
+ if (task.date_start.year == year) and (task.date_start.month == month) and (task.date_start.day == day) then
+ table.insert(tasks_layout, wibox.widget {
+ {
+ {
+ text = task.summary,
+ align = "left",
+ halign = "center",
+ font = "JetBrainsMono Nerd Font, bold 10",
+ widget = wibox.widget.textbox
+ },
+ margins = dpi(2),
+ widget = wibox.container.margin
+ },
+ fg = Theme_config.calendar.task.fg,
+ bg = Theme_config.calendar.task.bg,
+ shape = Theme_config.calendar.task.shape,
+ forced_height = dpi(20),
+ widget = wibox.container.background
+ })
+ end
+ end
+ return tasks_layout
+ end
+
+ if months[date.month].first_day ~= 1 then
+ -- Fill previous month days, i doubles as the day
+ local column = 1
+ local last_month = get_last_month(date)
+ local prev_month = date.month
+ local prev_year = date.year
+ if date.month == 1 then
+ prev_month = 12
+ last_month = months[12].length
+ else
+ last_month = months[date.month - 1].length
+ end
+ if date.month == 11 then
+ prev_year = date.year - 1
+ end
+ prev_month = prev_month - 1
+ for i = last_month - months[date.month].first_day + 2, last_month, 1 do
+ local border = Theme_config.calendar.day.border_color
+ local bg = Theme_config.calendar.day.bg_unfocus
+ local fg = Theme_config.calendar.day.fg_unfocus
+ if column == selected_day.col and 1 == selected_day.row then
+ border = Theme_config.calendar.day.today_border_color
+ bg = Theme_config.calendar.day.today_bg_focus
+ fg = Theme_config.calendar.day.today_fg_focus
+ end
+ local y = tonumber(os.date("%Y"))
+ local m = month_convert[tonumber(os.date("%m"))]
+ if m == 1 then
+ m = 12
+ end
+ if (i == date.day) and (m == prev_month) and (date.year == y) then
+ bg = Theme_config.calendar.day.bg_focus
+ fg = Theme_config.calendar.day.fg_focus
+ end
+ local day = wibox.widget {
+ {
+ {
+ {
+ {
+ {
+ {
+ { -- Day
+ widget = wibox.widget.textbox,
+ align = "center",
+ valign = "center",
+ text = math.floor(i),
+ id = "day_text",
+ },
+ widget = wibox.container.margin,
+ margins = dpi(2),
+ },
+ id = "day_bg",
+ widget = wibox.container.background,
+ bg = bg,
+ shape = Theme_config.calendar.day.shape,
+ fg = fg,
+ },
+ widget = wibox.container.place,
+ valign = "center",
+ halign = "center",
+ },
+ {
+ get_tasks_for_day(math.floor(i), prev_month, prev_year),
+ widget = wibox.container.margin,
+ margins = dpi(4)
+ },
+ id = "tasks",
+ spacing = dpi(4),
+ layout = wibox.layout.fixed.vertical
+ },
+ widget = wibox.container.margin,
+ top = dpi(4)
+ },
+ id = "background",
+ widget = wibox.container.background,
+ bg = Theme_config.calendar.day.bg_unfocus,
+ fg = Theme_config.calendar.day.fg_unfocus,
+ border_color = border,
+ border_width = Theme_config.calendar.day.border_width,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(0))
+ end
+ },
+ widget = wibox.container.constraint,
+ width = dpi(100),
+ height = dpi(120),
+ strategy = "exact"
+ }
+
+ -- update selected_day if the day is clicked
+ day:buttons(
+ gears.table.join(
+ awful.button({}, 1, function()
+ selected_day.col = column
+ selected_day.row = 1
+ day:emit_signal("day::update_selected")
+ end)
+ )
+ )
+
+ day:connect_signal("day::update_selected", function()
+ if column == selected_day.col and 1 == selected_day.row then
+ awesome.emit_signal("day::reset_border")
+ day.background.border_color = Theme_config.calendar.day.today_border_color
+ end
+ end)
+
+ awesome.connect_signal("day::reset_border", function()
+ day.background.border_color = Theme_config.calendar.day.border_color
+ end)
+
+ calendar_matrix:add_widget_at(day, 1, column)
+ column = column + 1
+ end
+ end
+
+ --Actual month days
+ local row = 1
+ local col = months[date.month].first_day
+ for i = 1, months[date.month].length, 1 do
+
+ local border = Theme_config.calendar.day.border_color
+ local fg = Theme_config.calendar.day.fg
+ local bg = Theme_config.calendar.day.bg
+ if col == selected_day.col and row == selected_day.row then
+ border = Theme_config.calendar.day.today_border_color
+ end
+
+ local m = month_convert[tonumber(os.date("%m"))]
+ local y = tonumber(os.date("%Y"))
+ if (i == date.day) and (date.month == m) and (date.year == y) then
+ bg = Theme_config.calendar.day.bg_focus
+ fg = Theme_config.calendar.day.fg_focus
+ end
+
+ local day = wibox.widget {
+ {
+ {
+ {
+ {
+ {
+ {
+ { -- Day
+ widget = wibox.widget.textbox,
+ align = "center",
+ valign = "center",
+ text = math.floor(i),
+ id = "day_text",
+ },
+ widget = wibox.container.margin,
+ margins = dpi(2),
+ },
+ id = "day_bg",
+ widget = wibox.container.background,
+ bg = bg,
+ shape = Theme_config.calendar.day.shape,
+ fg = fg,
+ },
+ widget = wibox.container.place,
+ valign = "center",
+ halign = "center",
+ },
+ {
+ get_tasks_for_day(math.floor(i), date.month, date.year),
+ widget = wibox.container.margin,
+ margins = dpi(4)
+ },
+ id = "tasks",
+ spacing = dpi(4),
+ layout = wibox.layout.fixed.vertical
+ },
+ widget = wibox.container.margin,
+ top = dpi(4)
+ },
+ id = "background",
+ widget = wibox.container.background,
+ bg = Theme_config.calendar.day.bg,
+ fg = Theme_config.calendar.day.fg,
+ border_color = border,
+ border_width = Theme_config.calendar.day.border_width,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(0))
+ end
+ },
+ widget = wibox.container.constraint,
+ width = dpi(100),
+ height = dpi(120),
+ strategy = "exact"
+ }
+
+ -- update selected_day if the day is clicked
+ day:buttons(
+ gears.table.join(
+ awful.button({}, 1, function()
+ selected_day.col = col
+ selected_day.row = row
+ day:emit_signal("day::update_selected")
+ end)
+ )
+ )
+
+ day:connect_signal("day::update_selected", function()
+ if col == selected_day.col and row == selected_day.row then
+ awesome.emit_signal("day::reset_border")
+ day.background.border_color = Theme_config.calendar.day.today_border_color
+ end
+ end)
+
+ awesome.connect_signal("day::reset_border", function()
+ day.background.border_color = Theme_config.calendar.day.border_color
+ end)
+
+ calendar_matrix:add_widget_at(day, row, col)
+ col = col + 1
+ if col == 8 then
+ col = 1
+ row = row + 1
+ end
+ end
+
+ --next month
+ local next_month = date.month
+ if date.month == 12 then
+ next_month = 1
+ else
+ next_month = next_month + 1
+ end
+
+ if months[date.month].last_day ~= 7 then
+ for i = 1, 7 - months[date.month].last_day, 1 do
+ local border = Theme_config.calendar.day.border_color
+ local fg = Theme_config.calendar.day.fg_unfocus
+ local bg = Theme_config.calendar.day.bg_unfocus
+ if i == selected_day.col and months[date.month].weeks == selected_day.row then
+ border = Theme_config.calendar.day.today_border_color
+ end
+ local m = month_convert[tonumber(os.date("%m")) + 1]
+ if m == 13 then
+ m = 1
+ end
+ local y = tonumber(os.date("%Y"))
+ if (i == date.day) and (next_month == m) and (date.year == y) then
+ bg = Theme_config.calendar.day.bg_focus
+ fg = Theme_config.calendar.day.fg_focus
+ end
+ local day = wibox.widget {
+ {
+ {
+ {
+ {
+ {
+ {
+ { -- Day
+ widget = wibox.widget.textbox,
+ align = "center",
+ valign = "center",
+ text = math.floor(i),
+ id = "day_text",
+ },
+ widget = wibox.container.margin,
+ margins = dpi(2),
+ },
+ id = "day_bg",
+ widget = wibox.container.background,
+ bg = bg,
+ shape = Theme_config.calendar.day.shape,
+ fg = fg,
+ },
+ widget = wibox.container.place,
+ valign = "center",
+ halign = "center",
+ },
+ {
+ get_tasks_for_day(math.floor(i), next_month, date.year),
+ widget = wibox.container.margin,
+ margins = dpi(4)
+ },
+ id = "tasks",
+ spacing = dpi(4),
+ layout = wibox.layout.fixed.vertical
+ },
+ widget = wibox.container.margin,
+ top = dpi(4)
+ },
+ id = "background",
+ widget = wibox.container.background,
+ bg = Theme_config.calendar.day.bg_unfocus,
+ fg = Theme_config.calendar.day.fg_unfocus,
+ border_color = border,
+ border_width = Theme_config.calendar.day.border_width,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(0))
+ end
+ },
+ widget = wibox.container.constraint,
+ width = dpi(100),
+ height = dpi(120),
+ strategy = "exact"
+ }
+
+ -- update selected_day if the day is clicked
+ day:buttons(
+ gears.table.join(
+ awful.button({}, 1, function()
+ selected_day.col = i
+ selected_day.row = months[date.month].weeks
+ day:emit_signal("day::update_selected")
+ end)
+ )
+ )
+
+ day:connect_signal("day::update_selected", function()
+ if i == selected_day.col and months[date.month].weeks == selected_day.row then
+ awesome.emit_signal("day::reset_border")
+ day.background.border_color = Theme_config.calendar.day.today_border_color
+ end
+ end)
+
+ awesome.connect_signal("day::reset_border", function()
+ day.background.border_color = Theme_config.calendar.day.border_color
+ end)
+ calendar_matrix:add_widget_at(day, months[date.month].weeks, months[date.month].last_day + i)
+ end
+ end
+
+ return calendar_matrix
+ end
+
+ local function create_calendar_week_num()
+ weeks:reset()
+ local actual_fucking_date = date.month + 2
+ if date.month == 11 then
+ actual_fucking_date = 1
+ elseif date.month == 12 then
+ actual_fucking_date = 2
+ end
+ local start_week = actual_fucking_date * 4 - 3
+ local weeknum = actual_fucking_date * 4 - 3
+ if get_date_weekday("01", date.month, date.year) ~= 1 then
+ weeknum = weeknum - 1
+ end
+ if actual_fucking_date == 1 then
+ weeknum = 52
+ end
+ for i = start_week, start_week + get_weeks_in_month(date.month, date.year) - 1, 1 do
+ weeks:add(wibox.widget {
+ {
+ {
+ text = weeknum,
+ id = "num",
+ align = "center",
+ valign = "top",
+ widget = wibox.widget.textbox,
+ },
+ id = "background",
+ fg = Theme_config.calendar.day.fg_unfocus,
+ widget = wibox.container.background,
+ },
+ strategy = "exact",
+ height = dpi(120),
+ width = dpi(40),
+ widget = wibox.container.constraint
+ })
+ if weeknum == 52 then
+ weeknum = 1
+ else
+ weeknum = weeknum + 1
+ end
+ end
+ return weeks
+ end
+
+ --- Calendar widget
+ local calendar = wibox.widget {
+ {
+ {
+ {
+ {
+ {
+ {
+ {
+ widget = wibox.widget.imagebox,
+ resize = false,
+ image = gears.color.recolor_image(icondir .. "add_ical.svg", Theme_config.calendar.add_ical.fg_focus),
+ halign = "center",
+ valign = "center"
+ },
+ id = "add_ical",
+ shape = Theme_config.calendar.add_ical.shape,
+ bg = Theme_config.calendar.add_ical.bg,
+ widget = wibox.container.background
+ },
+ widget = wibox.container.margin,
+ margins = dpi(4)
+ },
+ {
+ {
+ {
+ widget = wibox.widget.imagebox,
+ resize = false,
+ image = gears.color.recolor_image(icondir .. "add_task.svg", Theme_config.calendar.add_task.fg),
+ halign = "center",
+ valign = "center"
+ },
+ id = "add_task",
+ shape = Theme_config.calendar.add_task.shape,
+ bg = Theme_config.calendar.add_task.bg,
+ widget = wibox.container.background
+ },
+ widget = wibox.container.margin,
+ margins = dpi(4)
+ },
+ layout = wibox.layout.fixed.vertical
+ },
+ widget = wibox.container.constraint,
+ strategy = "exact",
+ height = dpi(75)
+ },
+ create_calendar_week_num(),
+ id = "weekdaysnum",
+ layout = wibox.layout.fixed.vertical
+ },
+ {
+ {
+ { --Header
+ { -- Month switcher
+ { -- Prev arrow
+ widget = wibox.widget.imagebox,
+ resize = true,
+ image = icondir .. "chevron-left.svg",
+ valign = "center",
+ halign = "center",
+ id = "prev_month",
+ },
+ {
+ { -- Month
+ widget = wibox.widget.textbox,
+ text = months_table[date.month],
+ id = "month",
+ valign = "center",
+ align = "center"
+ },
+ widget = wibox.container.constraint,
+ strategy = "exact",
+ width = dpi(150)
+ },
+ { -- Next arrow
+ widget = wibox.widget.imagebox,
+ resize = true,
+ image = icondir .. "chevron-right.svg",
+ valign = "center",
+ halign = "center",
+ id = "next_month",
+ },
+ layout = wibox.layout.fixed.horizontal
+ },
+ nil,
+ { -- Year switcher
+ { -- Prev arrow
+ widget = wibox.widget.imagebox,
+ resize = true,
+ image = icondir .. "chevron-left.svg",
+ valign = "center",
+ halign = "center",
+ id = "prev_year"
+ },
+ {
+ { -- Month
+ widget = wibox.widget.textbox,
+ text = date.year,
+ id = "year",
+ valign = "center",
+ align = "center"
+ },
+ widget = wibox.container.constraint,
+ strategy = "exact",
+ width = dpi(150)
+ },
+ { -- Next arrow
+ widget = wibox.widget.imagebox,
+ resize = true,
+ image = icondir .. "chevron-right.svg",
+ valign = "center",
+ halign = "center",
+ id = "next_year"
+ },
+ layout = wibox.layout.fixed.horizontal
+ },
+ layout = wibox.layout.align.horizontal
+ },
+ widget = wibox.container.constraint,
+ height = dpi(40),
+ strategy = "exact"
+ },
+ { -- Weekdays
+ create_weekdays(),
+ widget = wibox.container.background
+ },
+ create_calendar(),
+ id = "calendar",
+ spacing = dpi(5),
+ layout = wibox.layout.fixed.vertical
+ },
+ id = "lay1",
+ layout = wibox.layout.fixed.horizontal,
+ },
+ widget = wibox.container.background,
+ bg = Theme_config.calendar.bg,
+ border_color = Theme_config.calendar.border_color,
+ border_width = Theme_config.calendar.border_width,
+ border_strategy = "inner",
+ fg = Theme_config.calendar.fg,
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(4))
+ end
+ }
+
+ local add_ical = calendar:get_children_by_id("add_ical")[1]
+ local add_task = calendar:get_children_by_id("add_task")[1]
+
+ add_ical:buttons(
+ gears.table.join(
+ awful.button({}, 1, function()
+ awful.spawn.easy_async_with_shell(
+ "zenity --file-selection --title='Select an iCalendar file' --file-filter='iCalendar File | *.ics'",
+ function(path_to_file)
+ path_to_file = string.gsub(path_to_file, "\n", "")
+ if not path_to_file then return end
+ ical_parser.new(path_to_file)
+ tasks = create_tasks()
+ calendar:get_children_by_id("weekdaysnum")[1].children[2] = create_calendar_week_num()
+ calendar:get_children_by_id("calendar")[1].children[3] = create_calendar()
+ end
+ )
+ end)
+ )
+ )
+
+ Hover_signal(add_ical)
+ Hover_signal(add_task)
+
+ --- Popup that contains the calendar
+ local cal_popup = awful.popup {
+ widget = calendar,
+ screen = s,
+ ontop = true,
+ bg = "#00000000",
+ visible = false
+ }
+
+ --- Calendar switch month back
+ calendar:get_children_by_id("prev_month")[1]:buttons(
+ gears.table.join(
+ awful.button({}, 1, function()
+ date.month = date.month - 1
+ if date.month == 0 then
+ date.month = 12
+ end
+ if date.month == 10 then
+ date.year = date.year - 1
+ end
+ calendar:get_children_by_id("month")[1].text = months_table[date.month]
+ calendar:get_children_by_id("year")[1].text = date.year
+ calendar:get_children_by_id("weekdaysnum")[1].children[2] = create_calendar_week_num()
+ calendar:get_children_by_id("calendar")[1].children[3] = create_calendar()
+ end)
+ )
+ )
+
+ --- Calendar switch month forward
+ calendar:get_children_by_id("next_month")[1]:buttons(
+ gears.table.join(
+ awful.button({}, 1, function()
+ date.month = date.month + 1
+ if date.month == 13 then
+ date.month = 1
+ end
+ if date.month == 11 then
+ date.year = date.year + 1
+ end
+ calendar:get_children_by_id("month")[1].text = months_table[date.month]
+ calendar:get_children_by_id("year")[1].text = date.year
+ calendar:get_children_by_id("weekdaysnum")[1].children[2] = create_calendar_week_num()
+ calendar:get_children_by_id("calendar")[1].children[3] = create_calendar()
+ end)
+ )
+ )
+
+ --- Calendar switch year back
+ calendar:get_children_by_id("prev_year")[1]:buttons(
+ gears.table.join(
+ awful.button({}, 1, function()
+ date.year = date.year - 1
+ calendar:get_children_by_id("year")[1].text = date.year
+ calendar:get_children_by_id("weekdaysnum")[1].children[2] = create_calendar_week_num()
+ calendar:get_children_by_id("calendar")[1].children[3] = create_calendar()
+ end)
+ )
+ )
+
+ --- Calendar switch year forward
+ calendar:get_children_by_id("next_year")[1]:buttons(
+ gears.table.join(
+ awful.button({}, 1, function()
+ date.year = date.year + 1
+ calendar:get_children_by_id("year")[1].text = date.year
+ calendar:get_children_by_id("weekdaysnum")[1].children[2] = create_calendar_week_num()
+ calendar:get_children_by_id("calendar")[1].children[3] = create_calendar()
+ end)
+ )
+ )
+
+ --- Toggle calendar visibility
+ awesome.connect_signal("calendar::toggle", function(widget)
+ if s == mouse.screen then
+ cal_popup.x = 3765
+ cal_popup.y = 60
+ cal_popup.visible = not cal_popup.visible
+ end
+ end)
+
+end
diff --git a/awesome/src/modules/crylia_bar/dock.lua b/awesome/src/modules/crylia_bar/dock.lua
index b26c236..8517259 100644
--- a/awesome/src/modules/crylia_bar/dock.lua
+++ b/awesome/src/modules/crylia_bar/dock.lua
@@ -3,6 +3,7 @@
--------------------------------------------------------------------------------------------------------------
-- Awesome Libs
local awful = require("awful")
+local async = require("async")
local dpi = require("beautiful").xresources.apply_dpi
local Gio = require("lgi").Gio
local gears = require("gears")
@@ -25,7 +26,7 @@ return function(screen)
---@param size number The size of the widget
---@return widox.widget | nil The widget or nil if the program is not found
local function create_dock_element(program, size)
- if not program then return end
+
local dock_element = wibox.widget {
{
{
@@ -164,15 +165,14 @@ return function(screen)
end
local prog = json:decode(data:read("a"))
- if (not prog) or prog == "" then return end
+ data:close()
for _, pr in ipairs(prog) do
local indicators = { layout = wibox.layout.flex.horizontal, spacing = dpi(5) }
local col = Theme_config.dock.indicator_bg
for _, c in ipairs(client.get()) do
local icon_name = pr.icon
- if not c.class then return end
- if icon_name:match(string.lower(c.class)) or c.class:match(string.lower(icon_name)) or
- (string.lower(c.name) == string.lower(icon_name)) or c.name:match(string.lower(icon_name)) then
+ if icon_name:match(string.lower(c.class or c.name)) or c.class:match(string.lower(icon_name)) or
+ c.name:match(string.lower(icon_name)) then
if c == client.focus then
col = Theme_config.dock.indicator_focused_bg
elseif c.urgent then
@@ -253,9 +253,7 @@ return function(screen)
return
end
local dock_data = json:decode(data:read("a"))
- if (not dock_data) or dock_data == "" then
- return
- end
+ data:close()
for _, program in ipairs(dock_data) do
table.insert(dock_elements, create_dock_element(program, User_config.dock_icon_size))
end
diff --git a/awesome/src/modules/init.lua b/awesome/src/modules/init.lua
index bb70c77..6013147 100644
--- a/awesome/src/modules/init.lua
+++ b/awesome/src/modules/init.lua
@@ -27,5 +27,6 @@ awful.screen.connect_for_each_screen(
require("src.modules.notification-center.init")(s)
require("src.modules.window_switcher.init")(s)
require("src.modules.application_launcher.init")(s)
+ require("src.modules.calendar.calendar")(s)
end
)
diff --git a/awesome/src/modules/notification-center/init.lua b/awesome/src/modules/notification-center/init.lua
index 0719124..9d18df2 100644
--- a/awesome/src/modules/notification-center/init.lua
+++ b/awesome/src/modules/notification-center/init.lua
@@ -130,11 +130,46 @@ return function(s)
widget = wibox.container.place,
}
+ local rubato = require("src.lib.rubato")
+
+ local rubato_timed = rubato.timed { duration = 1, pos = 0 }
+
local toggle_button = wibox.widget {
{
- left_button,
- right_button,
- widget = wibox.layout.flex.horizontal
+ id = "background",
+ widget = wibox.widget {
+ fit = function(_, width, height)
+ return width, height
+ end,
+ draw = function(_, _, cr, width, height)
+ -- Clear for next drawing
+ --cr:set_operator(cairo.Operator.CLEAR);
+ local function move_dnd()
+ cr:set_source(gears.color(Theme_config.notification_center.dnd.bg));
+ cr:paint();
+ cr:set_source(gears.color(Theme_config.notification_center.dnd.disabled))
+ cr:move_to(rubato_timed.pos, 0)
+ local x = rubato_timed.pos
+ local y = 5
+ local newwidth = width / 2 - 10
+ local newheight = height - 10
+
+ local radius = height / 6.0
+ local degrees = math.pi / 180.0;
+
+ cr:new_sub_path()
+ cr:arc(x + newwidth - radius, y + radius, radius, -90 * degrees, 0 * degrees)
+ cr:arc(x + newwidth - radius, y + newheight - radius, radius, 0 * degrees, 90 * degrees)
+ cr:arc(x + radius, y + newheight - radius, radius, 90 * degrees, 180 * degrees)
+ cr:arc(x + radius, y + radius, radius, 180 * degrees, 270 * degrees)
+ cr:close_path()
+ cr:fill()
+ end
+
+ rubato_timed:subscribe(move_dnd)
+ rubato_timed.target = width / 2 + 5
+ end
+ }
},
active = false,
widget = wibox.container.background,
@@ -152,22 +187,20 @@ return function(s)
"button::press",
function()
if toggle_button.active then
- left_button.visible = true
- right_button.visible = false
toggle_button.active = not toggle_button.active
toggle_button.border_color = Theme_config.notification_center.dnd.border_disabled
User_config.dnd = false
+ rubato_timed.target = 5
else
- left_button.visible = false
- right_button.visible = true
toggle_button.active = not toggle_button.active
toggle_button.border_color = Theme_config.notification_center.dnd.border_enabled
User_config.dnd = true
+ rubato_timed.target = 50
end
end
)
- local dnd = wibox.widget { -- Clear all button
+ local dnd = wibox.widget {
{
{
{
@@ -348,12 +381,22 @@ return function(s)
end
)
+ local function mouse_leave()
+ notification_center.visible = false
+ end
+
+ awesome.connect_signal("notification_center::block_mouse_events", function()
+ notification_center:disconnect_signal("mouse::leave", mouse_leave)
+ end)
+
+ awesome.connect_signal("notification_center::unblock_mouse_events", function()
+ notification_center:connect_signal("mouse::leave", mouse_leave)
+ end)
+
-- Hide notification_center when mouse leaves it
notification_center:connect_signal(
"mouse::leave",
- function()
- notification_center.visible = false
- end
+ mouse_leave
)
-- Clear all notifications on button press
diff --git a/awesome/src/modules/notification-center/notification_list.lua b/awesome/src/modules/notification-center/notification_list.lua
index 51475f7..eb7efa9 100644
--- a/awesome/src/modules/notification-center/notification_list.lua
+++ b/awesome/src/modules/notification-center/notification_list.lua
@@ -15,7 +15,7 @@ local icondir = awful.util.getdir("config") .. "src/assets/icons/notifications/"
local nl = {}
nl.notification_list = { layout = require("src.lib.overflow_widget.overflow").vertical, scrollbar_width = 0,
- step = dpi(20), spacing = dpi(20) }
+ step = dpi(100), spacing = dpi(20) }
-- @param {table} notification
-- @return {widget} notifications_list
diff --git a/awesome/src/modules/notification-center/status_bars.lua b/awesome/src/modules/notification-center/status_bars.lua
index abe2b98..19ac63f 100644
--- a/awesome/src/modules/notification-center/status_bars.lua
+++ b/awesome/src/modules/notification-center/status_bars.lua
@@ -90,6 +90,14 @@ return function()
margins = dpi(10)
}
+ w:connect_signal("mouse::enter", function()
+ awesome.emit_signal("notification_center::block_mouse_events")
+ end)
+
+ w:connect_signal("mouse::leave", function()
+ awesome.emit_signal("notification_center::unblock_mouse_events")
+ end)
+
awesome.connect_signal(
"update::cpu_usage",
function(cpu_usage)
@@ -160,7 +168,13 @@ return function()
preferred_alignments = "middle",
margins = dpi(10)
}
+ w:connect_signal("mouse::enter", function()
+ awesome.emit_signal("notification_center::block_mouse_events")
+ end)
+ w:connect_signal("mouse::leave", function()
+ awesome.emit_signal("notification_center::unblock_mouse_events")
+ end)
awesome.connect_signal(
"update::cpu_temp",
function(cpu_temp)
@@ -239,7 +253,13 @@ return function()
preferred_alignments = "middle",
margins = dpi(10)
}
+ w:connect_signal("mouse::enter", function()
+ awesome.emit_signal("notification_center::block_mouse_events")
+ end)
+ w:connect_signal("mouse::leave", function()
+ awesome.emit_signal("notification_center::unblock_mouse_events")
+ end)
awesome.connect_signal(
"update::ram_widget",
function(MemTotal, _, MemAvailable)
@@ -312,7 +332,13 @@ return function()
preferred_alignments = "middle",
margins = dpi(10)
}
+ w:connect_signal("mouse::enter", function()
+ awesome.emit_signal("notification_center::block_mouse_events")
+ end)
+ w:connect_signal("mouse::leave", function()
+ awesome.emit_signal("notification_center::unblock_mouse_events")
+ end)
awesome.connect_signal(
"update::gpu_usage",
function(gpu_usage)
@@ -383,7 +409,13 @@ return function()
preferred_alignments = "middle",
margins = dpi(10)
}
+ w:connect_signal("mouse::enter", function()
+ awesome.emit_signal("notification_center::block_mouse_events")
+ end)
+ w:connect_signal("mouse::leave", function()
+ awesome.emit_signal("notification_center::unblock_mouse_events")
+ end)
awesome.connect_signal(
"update::gpu_temp",
function(gpu_temp)
@@ -472,7 +504,13 @@ return function()
preferred_alignments = "middle",
margins = dpi(10)
}
+ w:connect_signal("mouse::enter", function()
+ awesome.emit_signal("notification_center::block_mouse_events")
+ end)
+ w:connect_signal("mouse::leave", function()
+ awesome.emit_signal("notification_center::unblock_mouse_events")
+ end)
awesome.connect_signal(
"audio::get",
function(muted, volume)
@@ -563,7 +601,13 @@ return function()
preferred_alignments = "middle",
margins = dpi(10)
}
+ w:connect_signal("mouse::enter", function()
+ awesome.emit_signal("notification_center::block_mouse_events")
+ end)
+ w:connect_signal("mouse::leave", function()
+ awesome.emit_signal("notification_center::unblock_mouse_events")
+ end)
awesome.connect_signal(
"microphone::get",
function(muted, volume)
@@ -647,22 +691,20 @@ return function()
preferred_alignments = "middle",
margins = dpi(10)
}
+ w:connect_signal("mouse::enter", function()
+ awesome.emit_signal("notification_center::block_mouse_events")
+ end)
+ w:connect_signal("mouse::leave", function()
+ awesome.emit_signal("notification_center::unblock_mouse_events")
+ end)
awesome.connect_signal(
- "brightness::get",
- function(brightness)
- local icon = icondir .. "brightness/brightness"
- if brightness >= 0 and brightness < 34 then
- icon = icon .. "-low"
- elseif brightness >= 34 and brightness < 67 then
- icon = icon .. "-medium"
- elseif brightness >= 67 then
- icon = icon .. "-high"
- end
- w:get_children_by_id("icon1")[1].image = gears.color.recolor_image(icon .. ".svg",
+ "update::backlight",
+ function(backlight, backlight_icon)
+ w:get_children_by_id("icon1")[1].image = gears.color.recolor_image(backlight_icon,
Theme_config.notification_center.status_bar.backlight_color)
- tooltip.text = "Backlight: " .. brightness .. "%"
- rubato_timer.target = brightness
+ tooltip.text = "Backlight: " .. backlight .. "%"
+ rubato_timer.target = backlight
end
)
elseif widget == "battery" then
@@ -728,7 +770,13 @@ return function()
preferred_alignments = "middle",
margins = dpi(10)
}
+ w:connect_signal("mouse::enter", function()
+ awesome.emit_signal("notification_center::block_mouse_events")
+ end)
+ w:connect_signal("mouse::leave", function()
+ awesome.emit_signal("notification_center::unblock_mouse_events")
+ end)
awesome.connect_signal(
"update::battery_widget",
function(battery, battery_icon)
diff --git a/awesome/src/modules/volume_controller.lua b/awesome/src/modules/volume_controller.lua
index 7216706..42131a1 100644
--- a/awesome/src/modules/volume_controller.lua
+++ b/awesome/src/modules/volume_controller.lua
@@ -68,11 +68,13 @@ return function(s)
Theme_config.volume_controller.device_icon_color)
device.bg = Theme_config.volume_controller.device_headphones_selected_bg
device.fg = Theme_config.volume_controller.device_headphones_selected_fg
+ Hover_signal(device)
else
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "headphones.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color)
device.bg = Theme_config.volume_controller.device_bg
device.fg = Theme_config.volume_controller.device_headphones_fg
+ Hover_signal(device)
end
end
)
@@ -85,16 +87,17 @@ return function(s)
Theme_config.volume_controller.device_icon_color)
device.bg = Theme_config.volume_controller.device_headphones_selected_bg
device.fg = Theme_config.volume_controller.device_headphones_selected_fg
+ Hover_signal(device)
else
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "headphones.svg",
Theme_config.volume_controller.device_headphones_selected_icon_color)
device.bg = Theme_config.volume_controller.device_bg
device.fg = Theme_config.volume_controller.device_headphones_fg
+ Hover_signal(device)
end
end
)
awesome.emit_signal("update::bg_sink", node)
- Hover_signal(device)
else
device:connect_signal(
"button::press",
@@ -115,11 +118,13 @@ return function(s)
Theme_config.volume_controller.device_icon_color)
device.bg = Theme_config.volume_controller.device_microphone_selected_bg
device.fg = Theme_config.volume_controller.device_microphone_selected_fg
+ Hover_signal(device)
else
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "microphone.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color)
device.bg = Theme_config.volume_controller.device_bg
device.fg = Theme_config.volume_controller.device_microphone_fg
+ Hover_signal(device)
end
end
)
@@ -132,16 +137,17 @@ return function(s)
Theme_config.volume_controller.device_icon_color)
device.bg = Theme_config.volume_controller.device_microphone_selected_bg
device.fg = Theme_config.volume_controller.device_microphone_selected_fg
+ Hover_signal(device)
else
device:get_children_by_id("icon")[1].image = gears.color.recolor_image(icondir .. "microphone.svg",
Theme_config.volume_controller.device_microphone_selected_icon_color)
device.bg = Theme_config.volume_controller.device_bg
device.fg = Theme_config.volume_controller.device_microphone_fg
+ Hover_signal(device)
end
end
)
awesome.emit_signal("update::bg_source", node)
- Hover_signal(device)
end
return device
end
diff --git a/awesome/src/theme/theme_config.lua b/awesome/src/theme/theme_config.lua
index bbe03f7..31cddf0 100644
--- a/awesome/src/theme/theme_config.lua
+++ b/awesome/src/theme/theme_config.lua
@@ -144,6 +144,52 @@ Theme_config.tasklist = {
]] --
--#region Module Settings
+Theme_config.calendar = {
+ bg = color["Grey900"],
+ fg = color["Grey100"],
+ border_color = color["Grey800"],
+ border_width = dpi(2),
+ day = {
+ today_border_color = color["Blue200"],
+ bg = color["Grey900"],
+ bg_focus = color["Teal200"],
+ bg_unfocus = color["Grey900"],
+ fg = color["Grey100"],
+ fg_focus = color["Grey900"],
+ fg_unfocus = color["Grey600"],
+ border_color = color["Grey800"],
+ border_width = dpi(2),
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(4))
+ end,
+ },
+ task = {
+ bg = color["Purple200"],
+ fg = color["Grey900"],
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(4))
+ end,
+ },
+ weekdays = {
+ bg = color["Grey900"],
+ fg = color["Blue200"]
+ },
+ add_ical = {
+ bg = color["Red200"],
+ fg = color["Grey900"],
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(4))
+ end,
+ },
+ add_task = {
+ bg = color["LightBlue200"],
+ fg = color["Grey900"],
+ shape = function(cr, width, height)
+ gears.shape.rounded_rect(cr, width, height, dpi(4))
+ end,
+ }
+}
+
Theme_config.notification = {
border_color = color["Grey800"],
border_width = dpi(4),
diff --git a/awesome/src/theme/user_config.lua b/awesome/src/theme/user_config.lua
index c5c42aa..a14fe93 100644
--- a/awesome/src/theme/user_config.lua
+++ b/awesome/src/theme/user_config.lua
@@ -20,9 +20,11 @@ User_config = {
"picom --experimental-backends",
"xfce4-power-manager",
"light-locker --lock-on-suspend --lock-on-lid &",
+ "spotify",
+ "discord",
"/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1",
"setxkbmap -option caps:swapescape",
- "protonmail-bridge"
+ "jamesdsp"
},
--[[
@@ -45,7 +47,7 @@ User_config = {
"MEDIA_PLAYER"
More information at: https://lazka.github.io/pgi-docs/UPowerGlib-1.0/enums.html#UPowerGlib.DeviceKind.KEYBOARD
]] --
- battery_kind = "BATTERY",
+ battery_kind = "LINE_POWER",
--[[
If your battery is not found you can specify its path here.
@@ -191,8 +193,8 @@ User_config = {
"ram_usage",
"microphone",
"volume",
- "backlight",
- "battery"
+ "gpu_temp",
+ "gpu_usage"
},
--[[
@@ -275,8 +277,10 @@ User_config = {
"Tasklist"
},
right_bar = {
- "Battery",
- "Bluetooth",
+ "Gpu Usage",
+ "Gpu Temperature",
+ "Cpu Usage",
+ "Cpu Temperature",
"Audio",
"Keyboard Layout",
"Date",
diff --git a/awesome/src/tools/gio_icon_lookup.lua b/awesome/src/tools/gio_icon_lookup.lua
index b0479d8..c43411a 100644
--- a/awesome/src/tools/gio_icon_lookup.lua
+++ b/awesome/src/tools/gio_icon_lookup.lua
@@ -17,7 +17,6 @@ Gtk.IconTheme.set_custom_theme(gtk_theme, User_config.icon_theme)
---@param app Gio.AppInfo
---@return string path
function Get_gicon_path(app)
- if not app then return "" end
local icon_info = gtk_theme:lookup_by_gicon(app, 64, 0)
if icon_info then
local path = icon_info:get_filename()
@@ -37,12 +36,12 @@ function Get_icon(class, name)
name = string.lower(name or "")
for _, app in ipairs(app_list) do
local desktop_app_info = Gio.DesktopAppInfo.new(app_info.get_id(app))
- local icon_string = Gio.DesktopAppInfo.get_string(desktop_app_info, "Name")
+ local icon_string = Gio.DesktopAppInfo.get_string(desktop_app_info, "Icon")
if icon_string then
icon_string = string.lower(icon_string)
if icon_string:match(class) or class:match(icon_string) then
return Get_gicon_path(app_info.get_icon(app))
- elseif (icon_string == name) or icon_string:match(name) or name:match(icon_string) then
+ elseif icon_string:match(name) or name:match(icon_string) then
return Get_gicon_path(app_info.get_icon(app))
end
end
diff --git a/awesome/src/tools/helpers/backlight.lua b/awesome/src/tools/helpers/backlight.lua
index 66a814f..c80388c 100644
--- a/awesome/src/tools/helpers/backlight.lua
+++ b/awesome/src/tools/helpers/backlight.lua
@@ -3,7 +3,7 @@ local awful = require("awful")
BACKLIGHT_MAX_BRIGHTNESS = 0
BACKLIGHT_SEPS = 0
awful.spawn.easy_async_with_shell(
- "xfpm-power-backlight-helper --get-max-brightness",
+ "pkexec xfpm-power-backlight-helper --get-max-brightness",
function(stdout)
BACKLIGHT_MAX_BRIGHTNESS = tonumber(stdout)
BACKLIGHT_SEPS = BACKLIGHT_MAX_BRIGHTNESS / 100
@@ -15,7 +15,7 @@ awesome.connect_signal(
"brightness::update",
function()
awful.spawn.easy_async_with_shell(
- "xfpm-power-backlight-helper --get-brightness",
+ "pkexec xfpm-power-backlight-helper --get-brightness",
function(value)
awesome.emit_signal("brightness::get", math.floor((tonumber(value) - 1) / (BACKLIGHT_MAX_BRIGHTNESS - 1) * 100))
awesome.emit_signal("brightness::rerun")
@@ -23,5 +23,3 @@ awesome.connect_signal(
)
end
)
-
-awesome.emit_signal("brightness::update")
diff --git a/awesome/src/tools/helpers/init.lua b/awesome/src/tools/helpers/init.lua
index ac312c2..87470cb 100644
--- a/awesome/src/tools/helpers/init.lua
+++ b/awesome/src/tools/helpers/init.lua
@@ -5,4 +5,4 @@ require("src.tools.helpers.ram")
require("src.tools.helpers.gpu_usage")
require("src.tools.helpers.gpu_temp")
require("src.tools.helpers.audio")
-require("src.tools.helpers.backlight")
+--require("src.tools.helpers.backlight")
diff --git a/awesome/src/tools/ical_parser.lua b/awesome/src/tools/ical_parser.lua
new file mode 100644
index 0000000..7490f99
--- /dev/null
+++ b/awesome/src/tools/ical_parser.lua
@@ -0,0 +1,332 @@
+local ical = {}
+ical.VCALENDAR = {}
+ical._private = {}
+ical._private.parser = {}
+
+--[[
+ The structure of ical looks like this:
+ ical = {
+ VCALENDAR = {
+ PRODID = "...",
+ VERSION = "...",
+ CALSCALE = "...",
+ METHOD = "...",
+ X-WR-CALNAME = "...",
+ X-WR-CALDESC = "...",
+ X-WR-TIMEZONE = "...",
+ VTIMEZONE = {
+ TZID = "...",
+ TZURL = "...",
+ X-LIC-LOCATION = "...",
+ STANDARD = {
+ TZOFFSETFROM = "...",
+ TZOFFSETTO = "...",
+ TZNAME = "...",
+ DTSTART = "...",
+ TZRDATE = "...",
+ TZRULE = "...",
+ TZUNTIL = "...",
+ TZPERIOD = "...",
+ },
+ DAYLIGHT = {
+ TZOFFSETFROM = "...",
+ TZOFFSETTO = "...",
+ TZNAME = "...",
+ DTSTART = "...",
+ TZRDATE = "...",
+ TZRULE = "...",
+ TZUNTIL = "...",
+ TZPERIOD = "...",
+ },
+ },
+ VEVENT = {
+ UID = "...",
+ DTSTAMP = "...",
+ DTSTART = "...",
+ DTEND = "...",
+ SUMMARY = "...",
+ DESCRIPTION = "...",
+ LOCATION = "...",
+ RRULE = "...",
+ RDATE = "...",
+ EXDATE = "...",
+ CLASS = "...",
+ STATUS = "...",
+ TRANSP = "...",
+ SEQUENCE = "...",
+ ORGANIZER = "...",
+ ATTENDEE = "...",
+ CATEGORIES = "...",
+ PRIORITY = "...",
+ URL = "...",
+ UID = "...",
+ DTSTAMP = "...",
+]]
+
+---Takes a path to an .ical file then parses it into a lua table and returns it
+---@param path string Path to the .ical file
+---@return table | nil calendar New calendar table or nil on error
+function ical.new(path)
+ local handler = io.open(path, "r")
+ if not handler then return end
+
+ -- Check if the line is a BEGIN:VCALENDAR
+ local v, k = handler:read("l"):match("([A-Z]+):([A-Z]+)")
+
+ if v:match("BEGIN") and k:match("VCALENDAR") then
+ table.insert(ical.VCALENDAR, ical._private.parser.VCALENDAR(handler))
+ return ical
+ end
+ return ical
+end
+
+function ical._private.parser.VEVENT(handler)
+ local VEVENT = {}
+
+ while true do
+ local line = handler:read("l")
+
+ if not line or line:match("END:VEVENT") then
+ break
+ end
+
+ local v, k = line:match("(.*):(.*)")
+ if v:match("CREATED") then
+ VEVENT.CREATED = ical._private.parser.to_datetime(k)
+ elseif v:match("LAST-MODIFIED") then
+ VEVENT.LAST_MODIFIED = ical._private.parser.to_datetime(k)
+ elseif v:match("DTSTAMP") then
+ VEVENT.DTSTAMP = ical._private.parser.to_datetime(k)
+ elseif v:match("UID") then
+ VEVENT.UID = k
+ elseif v:match("SUMMARY") then
+ VEVENT.SUMMARY = k
+ elseif v:match("RRULE") then
+ VEVENT.RRULE = {
+ FREQ = k:match("FREQ=([A-Z]+)"),
+ UNTIL = ical._private.parser.to_datetime(k:match("UNTIL=([TZ0-9]+)")),
+ WKST = k:match("WKST=([A-Z]+)"),
+ COUNT = k:match("COUNT=([0-9]+)"),
+ INTERVAL = k:match("INTERVAL=([0-9]+)")
+ }
+ elseif v:match("DTSTART") then
+ VEVENT.DTSTART = {
+ DTSTART = ical._private.parser.to_datetime(k),
+ TZID = v:match("TZID=([a-zA-Z-\\/]+)"),
+ VALUE = v:match("VALUE=([A-Z]+)")
+ }
+ elseif v:match("DTEND") then
+ VEVENT.DTEND = {
+ DTEND = ical._private.parser.to_datetime(k),
+ TZID = v:match("TZID=([a-zA-Z-\\/]+)"),
+ VALUE = v:match("VALUE=([A-Z]+)")
+ }
+ elseif v:match("TRANSP") then
+ VEVENT.TRANSP = k
+ elseif v:match("LOCATION") then
+ VEVENT.LOCATION = k
+ elseif v:match("DESCRIPTION") then
+ VEVENT.DESCRIPTION = k
+ elseif v:match("URL") then
+ VEVENT.URL = {
+ URL = k,
+ VALUE = v:match("VALUE=([A-Z]+)")
+ }
+ elseif v:match("BEGIN") then
+ if k:match("VALARM") then
+ VEVENT.VALARM = ical._private.parser.VALARM(handler)
+ end
+ end
+ end
+
+ --VEVENT.duration = VEVENT.DTSTART.DTSTART - VEVENT.DTEND.DTEND
+
+ return VEVENT
+end
+
+function ical._private.parser.alarm_to_time(alarm)
+ if not alarm then return end
+ --Parse alarm into a time depending on its value. The value will be -PT15M where - mean before and with no leading - it means after. PT can be ignored and 15 is the time M then the unit where M is minute, H is out etc
+ local time = alarm:match("([-]?[0-9]+)[A-Z]")
+ local unit = alarm:match("[-]?[A-Z][A-Z][0-9]+([A-Z]*)")
+
+ return time .. unit
+end
+
+function ical._private.parser.VALARM(handler)
+ local VALARM = {}
+
+ while true do
+ local line = handler:read("l")
+
+ if not line or line:match("END:VALARM") then
+ break
+ end
+
+ local v, k = line:match("(.*):(.*)")
+ if v:match("ACTION") then
+ VALARM.ACTION = k
+ elseif v:match("TRIGGER;VALUE=DURATION") then
+ VALARM.TRIGGER = {
+ VALUE = v:match("VALUE=(.*):"),
+ TRIGGER = ical._private.parser.alarm_to_time(k)
+ }
+ elseif v:match("DESCRIPTION") then
+ VALARM.DESCRIPTION = k
+ end
+ end
+
+ return VALARM
+end
+
+function ical._private.parser.VCALENDAR(handler)
+ local VCALENDAR = {}
+ VCALENDAR.VEVENT = {}
+ VCALENDAR.VTIMEZONE = {}
+
+ while true do
+ local line = handler:read("l")
+
+ if not line or line:match("END:VCALENDAR") then
+ break
+ end
+
+ local v, k = line:match("(.*):(.*)")
+ if v and k then
+ if v:match("PRODID") then
+ VCALENDAR.PRODID = k
+ elseif v:match("VERSION") then
+ VCALENDAR.VERSION = k
+ elseif v:match("BEGIN") then
+ if k:match("VTIMEZONE") then
+ VCALENDAR.VTIMEZONE = ical._private.parser.VTIMEZONE(handler)
+ elseif k:match("VEVENT") then
+ table.insert(VCALENDAR.VEVENT, ical._private.parser.VEVENT(handler))
+ end
+ end
+ end
+ end
+
+ handler:close()
+ return VCALENDAR
+end
+
+function ical._private.parser.VTIMEZONE(handler)
+ local VTIMEZONE = {}
+
+ while true do
+ local line = handler:read("l")
+
+ if not line or line:match("END:VTIMEZONE") then
+ break
+ end
+
+ local v, k = line:match("(.*):(.*)")
+ if v:match("TZID") then
+ VTIMEZONE.TZID = k
+ end
+ if v:match("BEGIN") then
+ if k:match("DAYLIGHT") then
+ VTIMEZONE.DAYLIGHT = ical._private.parser.DAYLIGHT(handler)
+ elseif k:match("STANDARD") then
+ VTIMEZONE.STANDARD = ical._private.parser.STANDARD(handler)
+ end
+ end
+ end
+
+ return VTIMEZONE
+end
+
+function ical._private.parser.DAYLIGHT(handler)
+ local DAYLIGHT = {}
+
+ while true do
+ local line = handler:read("l")
+
+ if not line or line:match("END:DAYLIGHT") then
+ break
+ end
+
+ local v, k = line:match("(.*):(.*)")
+ if v:match("TZOFFSETFROM") then
+ DAYLIGHT.TZOFFSETFROM = ical._private.parser.offset(k)
+ elseif v:match("TZOFFSETTO") then
+ DAYLIGHT.TZOFFSETTO = ical._private.parser.offset(k)
+ elseif v:match("TZNAME") then
+ DAYLIGHT.TZNAME = k
+ elseif v:match("DTSTART") then
+ DAYLIGHT.DTSTART = ical._private.parser.to_datetime(k)
+ elseif v:match("RRULE") then
+ DAYLIGHT.RRULE = {
+ FREQ = k:match("FREQ=([A-Z]+)"),
+ BYDAY = k:match("BYDAY=([%+%-0-9A-Z,]+)"),
+ BYMONTH = k:match("BYMONTH=([0-9]+)")
+ }
+ end
+ end
+
+ return DAYLIGHT
+end
+
+---Parses the STANDARD property into a table
+---@param handler table
+---@return table STANDARD The STANDARD property as a table
+function ical._private.parser.STANDARD(handler)
+ local STANDARD = {}
+
+ -- Read each line until END:STANDARD is read
+ while true do
+ local line = handler:read("l")
+
+ if not line or line:match("END:STANDARD") then
+ break
+ end
+
+ -- Break down each line into the property:value
+ local v, k = line:match("(.*):(.*)")
+ if v:match("TZOFFSETFROM") then
+ STANDARD.TZOFFSETFROM = ical._private.parser.offset(k)
+ elseif v:match("TZOFFSETTO") then
+ STANDARD.TZOFFSETTO = ical._private.parser.offset(k)
+ elseif v:match("TZNAME") then
+ STANDARD.TZNAME = k
+ elseif v:match("DTSTART") then
+ STANDARD.DTSTART = ical._private.parser.to_datetime(k)
+ elseif v:match("RRULE") then
+ STANDARD.RRULE = {
+ FREQ = k:match("FREQ=([A-Z]+)"),
+ BYDAY = k:match("BYDAY=([%+%-0-9A-Z,]+)"),
+ BYMONTH = k:match("BYMONTH=([0-9]+)")
+ }
+ end
+ end
+
+ return STANDARD
+end
+
+---Parse the ical date time format into an os.time integer and the utc
+---@param datetime string The datetime from the ical
+---@return date|nil time Parsed os.time()
+---@return unknown|nil utc UTC identifier
+function ical._private.parser.to_datetime(datetime)
+ if not datetime then return end
+ local dt, utc = {}, nil
+
+ dt.year, dt.month, dt.day = datetime:match("^(%d%d%d%d)(%d%d)(%d%d)")
+ dt.hour, dt.min, dt.sec, utc = datetime:match("T(%d%d)(%d%d)(%d%d)(Z?)")
+
+ if (dt.hour == nil) or (dt.min == nil) or (dt.sec == nil) then
+ dt.hour, dt.min, dt.sec, utc = 0, 0, 0, nil
+ end
+
+ for k, v in pairs(dt) do dt[k] = tonumber(v) end
+ return dt, utc
+end
+
+function ical._private.parser.offset(offset)
+ local s, h, m = offset:match("([+-])(%d%d)(%d%d)")
+ if s == "+" then s = 1 else s = -1 end
+ return s * (tonumber(h) * 3600 + tonumber(m) * 60)
+end
+
+return ical
diff --git a/awesome/src/widgets/date.lua b/awesome/src/widgets/date.lua
index e631692..7b415fa 100644
--- a/awesome/src/widgets/date.lua
+++ b/awesome/src/widgets/date.lua
@@ -62,5 +62,13 @@ return function()
-- Signals
Hover_signal(date_widget)
+ date_widget:buttons {
+ gears.table.join(
+ awful.button({}, 1, function()
+ awesome.emit_signal("calendar::toggle", date_widget)
+ end)
+ )
+ }
+
return date_widget
end
diff --git a/awesome/src/widgets/kblayout.lua b/awesome/src/widgets/kblayout.lua
index b443c2d..6a9d2a4 100644
--- a/awesome/src/widgets/kblayout.lua
+++ b/awesome/src/widgets/kblayout.lua
@@ -214,6 +214,8 @@ return function(s)
keymap = keymap
}
+ Hover_signal(kb_layout_item)
+
awesome.connect_signal(
"update::background:kblayout",
function()