Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Josep M. Bach committed Aug 29, 2011
1 parent f6e9521 commit 7842d09
Show file tree
Hide file tree
Showing 13 changed files with 536 additions and 172 deletions.
28 changes: 21 additions & 7 deletions Readme.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -51,13 +51,10 @@ The clients will receive notifications via sound/growl (configurable in a
If you're not using OSX, try to install the `afplay` program manually or... If you're not using OSX, try to install the `afplay` program manually or...
send a patch to make it work with your OS :) send a patch to make it work with your OS :)


* The pomodoro schedule is (as of v0.0.3) hard-coded. It starts at 8:00 AM,
stops at 13:00 for lunch, and starts again at 13:20. In the following
versions this will be freely configurable.


## Configuration ## Configuration


### Client configuration

By default, both sound and visual notifications are displayed on each event. By default, both sound and visual notifications are displayed on each event.
If you want to configure this, create a file in your home directory named If you want to configure this, create a file in your home directory named
`.domodororc` with some YAML configuration: `.domodororc` with some YAML configuration:
Expand All @@ -66,8 +63,25 @@ If you want to configure this, create a file in your home directory named
$ echo "visual: true" >> ~/.domodororc $ echo "visual: true" >> ~/.domodororc
$ echo "sound: false" >> ~/.domodororc $ echo "sound: false" >> ~/.domodororc


## Copyright ### Server configuration


Copyright (c) 2011 Josep M. Bach. Released under the MIT license. Inside the server machine, to configure the pomodoro schedule, create a
`~/.domodororc` file with YAML configuration (the values provided below are
those that will be used by default if you don't specify them):


````yaml
server:
pomodoro_duration: 25 # in minutes
pomodoro_break: 5 # in minutes
long_break_after: 4 # pomodoros


day_start: "08:30"
day_end: "16:30"

lunch_time: "13:00"
lunch_duration: 30 # in minutes
````

## Copyright

Copyright (c) 2011 Josep M. Bach. Released under the MIT license.
2 changes: 2 additions & 0 deletions lib/domodoro.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,8 @@
require 'eventmachine' require 'eventmachine'


require "domodoro/version" require "domodoro/version"
require "domodoro/schedule"
require "domodoro/timepoint"
require "domodoro/config" require "domodoro/config"
require "domodoro/channel" require "domodoro/channel"
require "domodoro/server" require "domodoro/server"
Expand Down
34 changes: 8 additions & 26 deletions lib/domodoro/channel.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,6 +1,6 @@
module Domodoro module Domodoro
class Channel < EM::Channel class Channel < EM::Channel
def broadcast(hour, min) def broadcast(timestamp, schedule)
if ENV['DEBUG'] if ENV['DEBUG']
puts 'DEBUG MODE: Start on even minutes, stop on odd minutes' puts 'DEBUG MODE: Start on even minutes, stop on odd minutes'
if min % 2 == 0 if min % 2 == 0
Expand All @@ -13,31 +13,13 @@ def broadcast(hour, min)
return return
end end


if (hour >= 8 && hour < 13) action = schedule.to_hash[timestamp]
morning(min) if action
elsif (hour >= 13 && min >= 20) && next_action = schedule.action_after(timestamp)
afternoon(min) self << {
end :action => action,
end :next_action => next_action
def morning(min) }
case min
when 0, 30
puts "#{Time.now} - Starting pomodoro!"
self << :start
when 25, 55
puts "#{Time.now} - Pomodoro break!"
self << :stop
end
end

def afternoon(min)
case min
when 20, 50
puts "#{Time.now} - Starting pomodoro!"
self << :start
when 45, 15
puts "#{Time.now} - Pomodoro break!"
self << :stop
end end
end end
end end
Expand Down
77 changes: 60 additions & 17 deletions lib/domodoro/client.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -12,34 +12,49 @@ def connected=(value)
@connected = true @connected = true
end end


def next_action
@next_action
end

def next_action=(action)
@next_action = action
end

def start(host, port='9111') def start(host, port='9111')
Config.load Config.load_client_configuration
puts "#{Time.now} - Domodoro listening on #{host}:#{port}" puts "#{Time.now} - Domodoro listening on #{host}:#{port}"
puts "Visual notifications: #{Config.visual}" puts "Visual notifications: #{Config.visual}"
puts "Sound notifications: #{Config.sound}\n" puts "Sound notifications: #{Config.sound}\n"


EM.run do EM.run do
EM.connect(host, port) do |c| EM.connect(host, port) do |c|
c.extend EM::P::LineText2 c.extend EM::P::ObjectProtocol
def c.connection_completed def c.connection_completed
puts " - Connected to server!" puts " - Connected to server!"
Client.connected = true Client.connected = true
end end
def c.receive_line(line) def c.receive_object(object)
case line case object[:current_action].last
when /start/ when :start
puts " - Starting pomodoro!" puts "[#{object[:current_action]}] - Starting pomodoro!"
Client.work Client.work
when /stop/ when :stop
puts " - Pomodoro break!" puts "[#{object[:current_action]}] - Pomodoro break!"
Client.break Client.break
when :lunch
puts "[#{object[:current_action]}] - Lunch time!"
Client.lunch
when :go_home
puts "[#{object[:current_action]}] - Time to go home!"
Client.home
end end
Client.next_action = object[:next_action]
end end
end end
EM.add_periodic_timer(1) do EM.add_periodic_timer(1) do
EM.next_tick do EM.next_tick do
if Client.connected if Client.connected
print_time print_next_action
else else
puts 'Cannot connect to server. Is it running?' puts 'Cannot connect to server. Is it running?'
end end
Expand Down Expand Up @@ -71,20 +86,48 @@ def break
end end
end end


def lunch
EM.defer do
if Config.visual
Notify.notify "Domodoro", "Lunch time!"
end
if Config.sound
system("afplay #{path_to('lunch.wav')}")
end
end
end

def home
EM.defer do
if Config.visual
Notify.notify "Domodoro", "Time to go home!"
end
if Config.sound
system("afplay #{path_to('home.wav')}")
end
end
end

private private


def path_to(asset) def path_to(asset)
File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'assets', asset)) File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'assets', asset))
end end


def print_time def print_next_action
hour = Time.now.hour.to_s.rjust(2, '0') timestamp = Timepoint.new(Client.next_action.first)
min = Time.now.min.to_s.rjust(2, '0') action = case Client.next_action.last
secs = Time.now.sec.to_s.rjust(2, '0') when :start then "Pomodoro"
when :stop then "Pomodoro Break"
when :lunch then "Lunch time"
when :go_home then "Go home"

time_left = timestamp.left_until

$stdout.print "\r" $stdout.print "\r"
$stdout.print " " * 20 $stdout.print " " * 50
$stdout.print "\r" $stdout.print "\r"
$stdout.print "#{hour}:#{min}:#{secs}" $stdout.print "Next: #{action} in #{time_left}"
$stdout.flush $stdout.flush
end end


Expand Down
33 changes: 32 additions & 1 deletion lib/domodoro/config.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,11 +1,12 @@
require 'yaml' require 'yaml'
require 'ostruct'


module Domodoro module Domodoro
module Config module Config
attr_accessor :visual, :sound attr_accessor :visual, :sound
extend self extend self


def load def load_client_configuration
if File.exist?(File.expand_path('~/.domodororc')) if File.exist?(File.expand_path('~/.domodororc'))
file = YAML.load(File.read(File.expand_path('~/.domodororc'))) file = YAML.load(File.read(File.expand_path('~/.domodororc')))


Expand All @@ -16,5 +17,35 @@ def load
self.sound = true self.sound = true
end end
end end

def get_server_configuration
config = OpenStruct.new

if File.exist?(File.expand_path('~/.domodororc'))
file = YAML.load(File.read(File.expand_path('~/.domodororc')))['server']

config.pomodoro_duration = file['pomodoro_duration']
config.pomodoro_break = file['pomodoro_break']
config.long_break_after = file['long_break_after']

config.day_start = Timepoint.new(file['day_start'])
config.day_end = Timepoint.new(file['day_end'])

config.lunch_time = Timepoint.new(file['lunch_time'])
config.lunch_duration = file['lunch_duration']
end

config.pomodoro_duration ||= 25
config.pomodoro_break ||= 5
config.long_break_after ||= 4

config.day_start ||= Timepoint.new('08:30')
config.day_end ||= Timepoint.new('16:30')

config.lunch_time ||= Timepoint.new('13:00')
config.lunch_duration ||= 30

config
end
end end
end end
82 changes: 82 additions & 0 deletions lib/domodoro/schedule.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,82 @@
module Domodoro
class Schedule
def initialize
@times = {}
@config = Config.get_server_configuration
end

def generate!
# Key points
@times[@config.lunch_time.to_s] = :lunch
@times[@config.day_end.to_s] = :go_home



generate_pomodoros_between(@config.day_start, @config.lunch_time)
generate_pomodoros_between(@config.lunch_time + @config.lunch_duration, @config.day_end)
end

def to_hash
@times
end

def current_action(timestamp)
times = @times.dup

if times[timestamp]
minus_one = false
else
minus_one = true
times[timestamp] = :now
end

sorted = times.sort

idx = sorted.index do |element|
element == sorted.assoc(timestamp)
end

idx = idx - 1 if minus_one

sorted[idx]
end

def action_after(timestamp)
times = @times.dup
times[timestamp] ||= :now
sorted = times.sort

idx = sorted.index do |element|
element == sorted.assoc(timestamp)
end

sorted[idx + 1]
end

private

def generate_pomodoros_between(start, finish)
duration = @config.pomodoro_duration
pomodoro_break = @config.pomodoro_break

time = start
long_break_yet = 1

while time.before?(finish)
@times[time.to_s] = :start
time += duration

break unless time.before?(finish)

@times[time.to_s] = :stop

break_rest = pomodoro_break
break_rest *= 2 if long_break_yet == @config.long_break_after

time += break_rest

long_break_yet += 1
end
end
end
end
Loading

0 comments on commit 7842d09

Please sign in to comment.