├── README.md └── init.lua /README.md: -------------------------------------------------------------------------------- 1 | # Awmodoro 2 | ### Clutter-free Pomodoro sessions in Awesome WM 3 | The basic idea is to at start (with for instance a keybinding) 4 | * hide clutter (widgets/wibox) 5 | * show a very out-of-our-way and subtle indication of elapsed and left time 6 | 7 | and at stop 8 | * bring back user to the real world 9 | 10 | Awmodoro is in itself a very simple timer (with a progress bar ui) specifically made with regards to the [Pomodoro Technique](https://en.wikipedia.org/wiki/Pomodoro_Technique). 11 | It can be used as a regular widget, however - awmodoro provides the user with hooks allowing lua-code to be executed at start and end of each session. This allows for setup and teardown of distraction free environments. 12 | 13 | 14 | ## Usage 15 | cd ~/.config/awesome 16 | git clone git://github.com/optama/awmodoro.git 17 | 18 | Example configuration, in rc.lua: 19 | ```lua 20 | local awmodoro = require("awmodoro") 21 | 22 | --pomodoro wibox 23 | pomowibox = awful.wibox({ position = "top", screen = 1, height=4}) 24 | pomowibox.visible = false 25 | local pomodoro = awmodoro.new({ 26 | minutes = 25, 27 | do_notify = true, 28 | active_bg_color = '#313131', 29 | paused_bg_color = '#7746D7', 30 | fg_color = {type = "linear", from = {0,0}, to = {pomowibox.width, 0}, stops = {{0, "#AECF96"},{0.5, "#88A175"},{1, "#FF5656"}}}, 31 | width = pomowibox.width, 32 | height = pomowibox.height, 33 | 34 | begin_callback = function() 35 | for s = 1, screen.count() do 36 | mywibox[s].visible = false 37 | end 38 | pomowibox.visible = true 39 | end, 40 | 41 | finish_callback = function() 42 | for s = 1, screen.count() do 43 | mywibox[s].visible = true 44 | end 45 | pomowibox.visible = false 46 | end}) 47 | pomowibox:set_widget(pomodoro) 48 | ``` 49 | 50 | In globalkeys: 51 | ```lua 52 | awful.key({ modkey }, "p", function () pomodoro:toggle() end), 53 | awful.key({ modkey, "Shift" }, "p", function () pomodoro:finish() end), 54 | ``` 55 | 56 | This creates a separate minimal and initially hidden wibox containing only the awmodoro widget. 57 | We set callbacks to hide other wiboxes at start and to show them again when finished. 58 | We add a keyboard shortcut to start a session and yes one to also end one ;-) 59 | 60 | 61 | Default mouse bindings are 62 | * Button 1 Toggle pause/resume 63 | * Button 2 (mid) End session 64 | * Button 3 Reset timer 65 | 66 | These can be overriden by adding and changing 67 | ```lua 68 | pomodoro:buttons(awful.util.table.join( 69 | awful.button({ }, 1, function() pomodoro:toggle() end), 70 | awful.button({ }, 2, function() pomodoro:finish() end), 71 | awful.button({ }, 3, function() pomodoro:reset() end) 72 | )) 73 | ``` 74 | ## Widget parameters 75 | minutes Minutes defining duration of a session. 76 | active_bg_color Background color of progress bar when timer is running. 77 | paused_bg_color Background color of progress bar when timer is paused. 78 | fg_color Foreground color(s) of progress bar. 79 | do_notify Boolean value specifying wether notifications should be shown at begin, pause, resume, finish and reset. 80 | width Width of widget. 81 | height Height of widget. 82 | 83 | Colors are provided according to format specified by http://awesome.naquadah.org/doc/api/modules/gears.color.html 84 | 85 | ## Sound notification 86 | 87 | If you wish to be notified by sound when a Pomodoro ends, you may add this functionality to `finish_callback`. 88 | 89 | 1. Make sure you have a sound player, e.g. [aplay](http://linux.die.net/man/1/aplay) 90 | 2. Download a [bell sound] and put it somewhere accessible to awesome. 91 | 3. Modify init.lua and add a call to **finish_callback** 92 | 93 | E.g. 94 | ```lua 95 | finish_callback = function() 96 | awful.util.spawn("aplay /home/foo/sounds/bell.wav") 97 | for s = 1, screen.count() do 98 | mywibox[s].visible = true 99 | end 100 | pomowibox.visible = false 101 | end}) 102 | ``` 103 | 104 | ### Note 105 | If you prefer indivisible sessions (no ability to pause) then instead of pomodoro:toggle() use pomodoro:begin() and override mouse button 1 to something else but toggle/pause. 106 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | -- Author: Opi Matin 2 | 3 | local awful = require("awful") 4 | local naughty = require("naughty") 5 | local math = require("math") 6 | local string = require("string") 7 | local timer = timer 8 | local gears = require("gears") 9 | 10 | local setmetatable = setmetatable 11 | local ipairs = ipairs 12 | local base = require("wibox.widget.base") 13 | local cairo = require("lgi").cairo 14 | 15 | --module("awmodoro") 16 | 17 | 18 | 19 | local awmodoro = { mt = {} } 20 | local data = setmetatable({}, { __mode = "k" }) 21 | 22 | local properties = { "width", "height", "paused_bg_color", "active_bg_color", "fg_color", "seconds", "do_notify"} 23 | 24 | local function update(_awmodoro) 25 | data[_awmodoro].bar:set_value(data[_awmodoro].elapsed) 26 | _awmodoro:emit_signal("widget::updated") 27 | end 28 | 29 | function awmodoro.draw(_awmodoro, wibox, cr, width, height) 30 | data[_awmodoro].bar:draw(wibox, cr, width, height) 31 | end 32 | 33 | function awmodoro.fit(_awmodoro, width, height) 34 | return data[_awmodoro].width, data[_awmodoro].height 35 | end 36 | 37 | function awmodoro:begin() 38 | if not data[self].timer.started then 39 | if data[self].begin_callback then data[self].begin_callback() end 40 | data[self].elapsed = 0 41 | data[self].bar:set_background_color(data[self].active_bg_color) 42 | update(self) 43 | data[self].timer:start() 44 | if data[self].do_notify then naughty.notify({text = "Pomodoro Begin"}) end 45 | end 46 | end 47 | 48 | function awmodoro:pause() 49 | data[self].timer:stop() 50 | data[self].bar:set_background_color(data[self].paused_bg_color) 51 | update(self) 52 | if data[self].do_notify then naughty.notify({text = "Pomodoro Paused"}) end 53 | end 54 | 55 | function awmodoro:resume() 56 | data[self].bar:set_background_color(data[self].active_bg_color) 57 | update(self) 58 | data[self].timer:start() 59 | if data[self].do_notify then naughty.notify({text = "Pomodoro Resumed"}) end 60 | end 61 | 62 | function awmodoro:finish() 63 | data[self].timer:stop() 64 | data[self].elapsed = data[self].seconds 65 | update(self) 66 | if data[self].do_notify then naughty.notify({text = "Pomodoro Finished"}) end 67 | if data[self].finish_callback then data[self].finish_callback() end 68 | end 69 | 70 | function awmodoro:reset() 71 | data[self].elapsed = 0 72 | update(self) 73 | if data[self].do_notify then naughty.notify({text = "Pomodoro Reset"}) end 74 | end 75 | 76 | function awmodoro:toggle() 77 | if data[self].timer.started then 78 | self:pause() 79 | elseif data[self].elapsed == 0 or data[self].elapsed == data[self].seconds then 80 | self:begin() 81 | else 82 | self:resume() 83 | end 84 | end 85 | 86 | for _, prop in ipairs(properties) do 87 | if not awmodoro["set_" .. prop] then 88 | awmodoro["set_" .. prop] = function(_awmodoro, value) 89 | data[_awmodoro][prop] = value 90 | _awmodoro:emit_signal("widget::updated") 91 | return _awmodoro 92 | end 93 | end 94 | end 95 | 96 | function awmodoro.new(args) 97 | local args = args or {} 98 | 99 | local width = args.width or 20 100 | local height = args.height or 100 101 | local paused_bg_color = args.paused_bg_color or '#FF732F' 102 | local active_bg_color = args.active_bg_color or '#494B4F' 103 | local seconds = (args.minutes and args.minutes * 60) or 25*60 104 | 105 | local fg_color = args.fg_color or {type = "linear", from = {0,0}, to = {width, 0}, stops = {{0, "#AECF96"},{0.5, "#88A175"},{1, "#FF5656"}}} 106 | local do_notify = args.do_notify or false 107 | 108 | local _awmodoro = base.make_widget() 109 | 110 | local bar = awful.widget.progressbar.new({width = width, height = height}) 111 | 112 | data[_awmodoro] = { width = width, height = height, seconds = seconds, elapsed = 0, timer = timer({ timeout = 1 }), bar = bar, active_bg_color = active_bg_color, paused_bg_color = paused_bg_color, do_notify = do_notify} 113 | 114 | if args.finish_callback then data[_awmodoro].finish_callback = args.finish_callback end 115 | if args.begin_callback then data[_awmodoro].begin_callback = args.begin_callback end 116 | 117 | _awmodoro.draw = awmodoro.draw 118 | _awmodoro.fit = awmodoro.fit 119 | _awmodoro.toggle = awmodoro.toggle 120 | _awmodoro.begin = awmodoro.begin 121 | _awmodoro.pause = awmodoro.pause 122 | _awmodoro.resume = awmodoro.resume 123 | _awmodoro.finish = awmodoro.finish 124 | _awmodoro.reset = awmodoro.reset 125 | 126 | data[_awmodoro].timer:connect_signal("timeout", function(c) 127 | data[_awmodoro].elapsed = data[_awmodoro].elapsed + 1 128 | update(_awmodoro) 129 | if data[_awmodoro].elapsed >= data[_awmodoro].seconds then 130 | _awmodoro:finish() 131 | end 132 | end) 133 | 134 | bar:set_width(width) 135 | bar:set_height(height) 136 | bar:set_vertical(false) 137 | bar:set_max_value(seconds) 138 | bar:set_background_color(active_bg_color) 139 | bar:set_color(fg_color) 140 | 141 | _awmodoro:buttons(awful.util.table.join( 142 | awful.button({ }, 1, function() _awmodoro:toggle() end), 143 | awful.button({ }, 2, function() _awmodoro:finish() end), 144 | awful.button({ }, 3, function() _awmodoro:reset() end) 145 | )) 146 | 147 | local pomodoro_tooltip = awful.tooltip({ 148 | objects = { _awmodoro }, 149 | timer_function = function() 150 | local elapsed = data[_awmodoro].elapsed 151 | local left = data[_awmodoro].seconds - data[_awmodoro].elapsed 152 | 153 | local tip = string.format("%-7s\t%02d:%02d\n%-7s\t%02d:%02d", "Elapsed", math.floor(elapsed / 60), elapsed % 60, "Left", math.floor(left/60), left%60) 154 | if not data[_awmodoro].timer.started then 155 | tip = tip .. "\nNot running" 156 | end 157 | return tip 158 | end}) 159 | 160 | return _awmodoro 161 | end 162 | 163 | function awmodoro.mt:__call(...) 164 | return awmodoro.new(...) 165 | end 166 | 167 | return setmetatable(awmodoro, awmodoro.mt) 168 | --------------------------------------------------------------------------------