Created
August 27, 2010 15:19
-
-
Save biangle/553555 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| task: 25 | |
| break: 5 | |
| coffee: 30 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #encoding: utf-8 | |
| # | |
| # PomTk - GUI utility for Pomodoro technique via Ruby/Tk. | |
| # | |
| # Author: biangle <[email protected]> | |
| # License: MIT License | |
| # | |
| require 'tk' | |
| require 'logger' | |
| require 'fileutils' | |
| require 'yaml' | |
| class PomTk | |
| PROGNAME = 'PomTk'.freeze | |
| VERSION = '0.0.1'.freeze | |
| LOG_DIR = File.join(ENV['HOME'], '.pomtk').freeze | |
| LOG_NAME = 'pom.log'.freeze | |
| LOG_AGE = 'daily'.freeze | |
| CONFIG_PATH = File.join(ENV['HOME'], '.pomtk.yaml').freeze | |
| DEFAULT_CONFIG = { 'task' => 25, 'break' => 5, 'coffee' => 30 }.freeze | |
| # Simple timer class. | |
| class Timer | |
| # Create a new Timer object with waiting seconds. | |
| def initialize(sec) | |
| @sec = sec | |
| @start_time = nil | |
| @thread = nil | |
| end | |
| # Launch a new thread and return immediatly. | |
| # The thread executes the given block after the timer seconds. | |
| def wait_and | |
| @thread = Thread.new do | |
| @start_time = Time.now | |
| sleep @sec | |
| yield | |
| end | |
| end | |
| # Stop the timer thread explicitly. | |
| def stop | |
| @thread.stop | |
| @thread = nil | |
| end | |
| # Rest seconds. | |
| def rest | |
| @sec - (Time.now - @start_time) | |
| end | |
| end # class Timer | |
| # Ruby/Tk extensions | |
| class ::TkButton | |
| def disable | |
| state 'disabled' | |
| end | |
| def enable | |
| state 'normal' | |
| end | |
| end # class TkButton | |
| # | |
| # Class methods | |
| # | |
| def self.launch | |
| new.launch | |
| end | |
| # | |
| # Instance methods | |
| # | |
| attr_reader :start_button | |
| def initialize | |
| ensure_log_dir | |
| @config = load_config | |
| @log = create_logger | |
| @log.info sprintf('%s start (task: %d, break: %d, coffee: %d [min]).', | |
| program_name, @config['task'], | |
| @config['break'], @config['coffee']) | |
| @pom_count = 1 | |
| @timer = Timer.new(@config['task'] * 60) | |
| @break_timer = Timer.new(@config['break'] * 60) | |
| @coffee_timer = Timer.new(@config['coffee'] * 60) | |
| @display = nil | |
| @start_button = nil | |
| create_window | |
| end | |
| def ensure_log_dir | |
| FileUtils.mkdir_p LOG_DIR | |
| end | |
| def create_logger | |
| logger = Logger.new(File.join(LOG_DIR, LOG_NAME), LOG_AGE) | |
| logger.progname = program_name | |
| logger.formatter = proc {|severity, datetime, progname, message| | |
| "[#{datetime.strftime('%H:%M:%S')}] #{message}\n" | |
| } | |
| logger.level = Logger::INFO | |
| logger | |
| end | |
| def program_name | |
| "#{PROGNAME} v#{VERSION}" | |
| end | |
| def load_config | |
| return DEFAULT_CONFIG unless File.file?(CONFIG_PATH) | |
| DEFAULT_CONFIG.merge YAML.load_file(CONFIG_PATH) | |
| end | |
| def launch | |
| Tk.mainloop | |
| @log.info 'quit.' | |
| @log.close | |
| end | |
| def create_window | |
| Tk.root.title = program_name | |
| @display = TkLabel.new(:text => '0 poms').pack(:fill => :x) | |
| button_proc = proc { | |
| start_button.disable | |
| start_countdown | |
| } | |
| @start_button = TkButton.new(:text => 'START', | |
| :command => button_proc).pack | |
| end | |
| def start_countdown | |
| display sprintf('pomodoro %d.', @pom_count) | |
| @start_button.text = 'RUNNING' | |
| @timer.wait_and do | |
| @log.info "DONE: " + guess_what_task | |
| take_break | |
| end | |
| end | |
| def display(msg) | |
| @display.text = msg | |
| @log.info msg | |
| end | |
| def guess_what_task | |
| window = TkToplevel.new | |
| window.title = %q{It's time to break!} | |
| TkLabel.new(window) do | |
| text %q{It's time to break! What task have you finished?} | |
| pack | |
| end | |
| entry = TkEntry.new(window).pack(:fill => :x) | |
| value = nil | |
| thread = Thread.new{ Thread.stop; value = entry.value; window.destroy } | |
| entry.bind('KeyPress-Return'){ thread.run } | |
| window.protocol("WM_DELETE_WINDOW"){ thread.run } | |
| window.attributes(:topmost, 1) | |
| entry.focus | |
| thread.join | |
| Tk.root.attributes(:topmost, 1) | |
| value | |
| end | |
| def take_break | |
| if 0 == (@pom_count % 4) | |
| display 'coffee break.' | |
| @coffee_timer.wait_and{ finish_pom } | |
| return | |
| end | |
| display 'break.' | |
| @break_timer.wait_and{ finish_pom } | |
| end | |
| def finish_pom | |
| @log.info sprintf('pomodoro %d finished.', @pom_count) | |
| @display.text = sprintf('%d poms', @pom_count) | |
| @start_button.text = 'START' | |
| @pom_count += 1 | |
| @start_button.enable | |
| end | |
| end # class PomTk |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env rubyw | |
| #encoding: utf-8 | |
| # | |
| # PomTk - GUI utility for Pomodoro technique via Ruby/Tk. | |
| # | |
| # Author: biangle <[email protected]> | |
| # License: MIT License | |
| # | |
| require 'rubygems' | |
| require 'pomtk' | |
| PomTk.launch |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment