#!usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'io/console' ; require 'csv' ; require 'date' ; require 'timeout'
#プログラム説明
#テーマ・目的:これは、「簡単にスケジュールやTo doを立てたい!!」という人のために作ったプログラムです。
#きっかけ :家族が、たくさんある予定を一括で見られないと言っているのを聞いたから。また自分の使っているスケジュールアプリの操作があまりにも難解だったから。
#目標 :スケジュールの設定・カレンダー・時計など、スケジューリングに必要なものを一元化する。そして操作も簡単にする!
#結果・展望 :↑に挙げた3つは概ね完成できた。操作もほぼ矢印キーとEnterキーで完結するようにした。今度は時計などをもっと見やすくしたり、カレンダーを祝日対応にしたり、予定があるかカレンダーに表示できるようにしたい。
#他のネタ :個人発表のMy Ruby Guide
# 暇をつぶす、もしくは頭を鍛えるゲーム(マインスイーパーなど)
# メモ帳
Funcs = [:Schedules, :Calendar, :Clock, :End]
Schedules = CSV.read('j2405_last.csv', headers: true)
Items = ["予定", "日程", "場所", "メモ"]
LOT = 7 # lines of text in "Schedules"
Modes = ["追加", "編集", "表示", "完了", "前", "次", "<戻る"]
Frame = "+------------\e[1B\e[13D|%02d \e[1B\e[13D| \e[1B\e[13D| " # calendar's frame
Today = Date.today; status, num, mode, page, year, mon = :MENU, nil, 0, 0, Today.year, Today.month; $, = "\n"
class Object
def plus(num1, num2); num2 ? (self + num1) % num2 : self + num1 end
end
Arrows = {'A'=>-1, 'D'=>-2, 'B'=>1, 'C'=>2}
def select(arrow = false, apart = false, num = 0, max = nil)
loop do
case STDIN.getch
when "\e"
if arrow
STDIN.getch; char = STDIN.getch; val = apart ? Arrows[char] : Arrows[char] <=> 0
return $input = num.plus(val, max)
end
when "\r", " "
return $input = nil
end
end
end
def deco(text, bool = true, a: 7, b: 4); "\e[#{bool ? a : b}m#{text}\e[m" end
def lineup(arr, var, sep = $,, st = 0, fin = nil); arr[st..fin].map.with_index(st % arr.length) { |item, i| deco(arr[i], var == i) }.join(sep) end # arr を並べあげる。
def disp(item, mode, text, arrow = " -> ", str = $/); text ||= ""; print nil, nil, " \e[1m#{item}\e[m", text; print arrow if mode == 1; if mode < 2; gets(str).chomp("") end end
begin
until status == :End
system "clear" ; system "tput civis" ; puts "\e[0;1m#{status}\e[m"
num ||= 0; lines = `tput lines`.chomp.to_i - LOT
case status
when :MENU
puts "リマインダへようこそ!", nil, "機能を選択・決定してください。(矢印キー・Enter/Return)", lineup(Funcs.map { |sym| " #{sym}" }, num); select(true, false, num, Funcs.length)
status = Funcs[num] unless $input; num = $input
when :Schedules
if lines > 0
pages_all = (Schedules.length.to_r / lines).ceil
puts "#{deco(Modes[-1], mode == Modes.length-1)}", nil, " 予定を #{lineup(Modes, mode, " ", 0, 3)} する(←→) ページ #{page + 1}/#{pages_all} #{lineup(Modes, mode, "|", Modes.length-3, Modes.length-2)}", " 予定を選択(↑↓)", nil, Schedules[lines*page...lines*(page+1)].map.with_index { |row, i| " \e[1;97m#{deco(row['schedule'], (1..3) === mode && num == i)} \e[38;5;250m-#{row['date']}・#{row['place']}\e[m" }
case select(true, true)
when -1, 1
num = num.plus($input, Schedules.length)
when -2, 2
mode = mode.plus($input/2, Modes.length)
else
case mode
when 0..2
system "clear" ; system "tput cnorm" if mode < 2 ; data, arr = Schedules[page*lines + num], []
3.times { |i| arr[i] = disp(Items[i], mode, (data[i] if mode > 0)) }; arr[3] = disp("メモ(入力時は2連続の改行で終了)", mode, (data['memo'] if mode > 0), "\n -> \n", "\n\n"); select if mode == 2
Schedules.delete(page*lines + num) if mode == 1; Schedules << arr if mode < 2
when 3
Schedules.delete(page*lines + num); num -= 1 if num > 0; page -= 1 if page > pages_all
when 4
page = page.plus(-1, pages_all)
when 5
page = page.plus(1, pages_all)
else
status, num, mode = :MENU, nil, 0
end
end
else
puts "\e[7m<戻る\e[m", nil, " Terminalの大きさが小さすぎます。", " 画面サイズを大きくしてください。"; select; status = :MENU
end
when :Calendar
case mon
when nil..0
year -= 1; mon = 12
when 13..nil
year += 1; mon = 1
end
calendar = Array.new(6) { Array.new(7) }.map.with_index { |week, nth| week.map.with_index(1) { |day, wday| day = nth*7 + wday - Date.new(year, mon, 1).wday; day > 0 && Date.valid_date?(year, mon, day) ? day : nil } }
puts "\e[4m<戻る(Enter)\e[m", nil, " \e[4m#{year}年 #{mon}月 のカレンダー (矢印キーで移動)\e[m",
calendar.map.with_index { |week, nth| week.map.with_index { |day, wday| sprintf("\e[#{nth*4 + 6};#{wday*13 + 3}H\e[1;107;#{case wday when 0; 31 when 6; 34 else; 30 end}m#{Frame}\e[m", day ? day : 0).gsub("00", "--") } }
select(true) ? mon += $input : status = :MENU
when :Clock
time = Time.now
Timeout.timeout(1 - time.nsec.to_r/10**9) do
puts "\e[4;7m<戻る(Enter)\e[m", nil, sprintf(" \e[1;7m#{time.year}/#{time.month}/#{time.day} 現在時刻 %02d : %02d\e[0;7;100m : %02d\e[m", time.hour, time.min, time.sec); select; status = :MENU
end
else
puts "\e[7m<戻る(Enter)\e[m", nil, " 問題が発生しました。"; select; status = :MENU
end
end
rescue Timeout::Error
retry
ensure
system "clear" ; system "tput cnorm" ; puts "\e[mシステムを終了します。", "またのご利用をお待ちしております。(*˘_˘*)"
CSV.open('j2405_last.csv', 'w') { |file| Schedules.to_a.each { |row| file << row } }
end