Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use message box to fix #12 that was not solve in ctimer_db branch #16

Merged
merged 18 commits into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Features
* Provide a Tkinter GUI window for the ease of use for users.
* Set 25 mins for focus time, and 5 mins for break time.
* Set 8 clocks as aim for a day.
* Goals / feedback of each clock & time span per day is kept in a local SQL database (named ctimer.db). Use command line tool sqlite3 you could check the entries.

* TODO BUGFIX:
- self.display.config updates appears after the voice_messages (os.subprocess("say ...")
Expand All @@ -40,6 +41,14 @@ Features
- Allows notes taking during the clock (note interruption, how many pauses you took etc.)
- Add tick-tock sound when clocks start.

# Note: For checking the sqlite database
A. drag and drop: https://inloop.github.io/sqlite-viewer/
B. in command line
1. >>> sqlite3 ./data/ctimer.db
2. >>> select * from clock_details; <---remember the ";" in the end
The entries should show! If not, try
3. .tables
This should show clock_details

Installation
------------
Expand Down
13 changes: 11 additions & 2 deletions concentratetimer/cli.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
"""Console script for concentratetimer."""
from concentratetimer import concentratetimer
import tkinter as tk
import concentratetimer.ctimer_db as db
import sys

from subprocess import Popen, PIPE
import os

def main():
# can also prompt user to enter a file path to store the database, but next time when the program launch
# it has to find it automatically. "from tkinter import filedialog"
path = os.path.dirname(concentratetimer.__file__).rsplit("/",1)[0]
db_file = f"{path}/data/ctimer.db"
db.create_connection(db_file) # create if not exist
root = tk.Tk()
app = concentratetimer.ConcentrateTimer(master=root)
app = concentratetimer.ConcentrateTimer(master=root, db_file=db_file)
app.mainloop()


return 0


Expand Down
64 changes: 40 additions & 24 deletions concentratetimer/concentratetimer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
from datetime import date
import tkinter as tk
from tkinter import simpledialog
# TODO: check software licences
from tkinter import messagebox as mbox
import concentratetimer.ctimer_db as db
# This code is an implementation upon the pomodoro technique from Cirillo, Francesco. If there is any ablation toward
# their copyright, it is not our intention.
# TODO: check pomodoro trademark guidelines
# https://francescocirillo.com/pages/pomodoro-trademark-guidelines

def time_print(time):
mins, secs = divmod(time, 60)
Expand All @@ -16,12 +15,14 @@ def time_print(time):


class ConcentrateTimer(tk.Frame):
def __init__(self, master=None):
def __init__(self, master=None, db_file=None):
super().__init__(master)
self.db_file = db_file
self.master = master
master.title("Pomodoro Timer")
self.test_volume()
#self.data = Meta(set_time=2, break_time=2, long_break_time=5, long_break_clock_count=2)
# For testing:
#self.data = Meta(set_time=10, break_time=3, long_break_time=5, long_break_clock_count=2)
self.data = Meta()
self.clock_ticking = False
self.is_break = False
Expand All @@ -34,6 +35,7 @@ def __init__(self, master=None):
self.pack()
self.create_widgets()
self.goal = None
self.clock_details = None

def create_widgets(self):
self.display = tk.Label(self, height=3, width=10, font=("Arial", 30), textvariable="")
Expand Down Expand Up @@ -69,14 +71,21 @@ def create_widgets(self):

def get_goal(self):
# TODO: get all goals for all clocks for the day
self.goal = simpledialog.askstring(title="Set your goals",
prompt="What's your goal for this clock:")
while not self.goal:
self.goal = simpledialog.askstring(title="Set Your Goals",
prompt="Empty Goal Is Not Allow. What's Your Goal for This Clock:")

self.goal_show_label["text"] = f"Goal: {self.goal}"

self.clock_details.task_description = simpledialog.askstring(title="Set your goals",
prompt="What's your goal for this clock:")
self.goal_show_label["text"] = f"Goal: {self.clock_details.task_description}"

def ask_reached_goal_reason(self):
self.clock_details.reached_bool = mbox.askyesno("Goal reached?",
"Did you finish your goal?",
parent=self)
if self.clock_details.reached_bool is False:
self.clock_details.reason = simpledialog.askstring("Goal reached description",
"What happened? "
"What was a suprise? \n"
"What needs to modify to "
"have a realistic goal? ",
parent=self)

def countdown(self):
if self.clock_ticking:
Expand All @@ -85,11 +94,12 @@ def countdown(self):
self.display.config(text=time_print(self.remaining_time))
else:
self.remaining_time = 0
# TODO: self.display.config updates appears after the voice_messages (os.subprocess("say ..."))
# TODO: 00:00 does not show.
# Finish a clock
if self.is_break == False:
self.display.config(text="Done!")
self.data.total_clock_count += 1
self.clock_details.clock_count = self.data.total_clock_count
self.clock_details.end_clock = time.time()
self.total_clock_counts.config(text=f"Total clocks: {self.data.total_clock_count}")
if self.data.total_clock_count % self.long_break_clock_count == 0:
self.remaining_time = self.set_long_break_time
Expand All @@ -98,8 +108,13 @@ def countdown(self):
self.voice_message("done")
self.is_break = True
self.display['fg'] = "Green"
self.ask_reached_goal_reason()
else:
# break is over. Record break over time.
self.voice_message("break_over")
self.clock_details.end_break = time.time()
# TODO: Bug fix --This is reached before reason is filled. check line 134
db.db_add_clock_details(self.db_file, self.clock_details)
self.is_break = False
self.remaining_time = self.set_time
self.display.config(text=time_print(self.set_time))
Expand All @@ -122,7 +137,8 @@ def voice_message(self, message_type):
message = f"Beebeebeebee beebee. Done. You have achieved {self.data.total_clock_count} " \
f"clocks today. Enjoy your break."
elif message_type == "start":
message = "ready? set your goal."
# TODO: if starting a new clock, new message: ready? set your goal
message = "ready? Start."
elif message_type == "pause":
message = "Pause"
elif message_type == "stop":
Expand All @@ -133,14 +149,16 @@ def voice_message(self, message_type):
subprocess.run(command)

def start_pause(self):
# start clock
if self.clock_ticking == False:
self.voice_message("start")
# only asking when the clock starts at the very beginning
### starting a new clock

if self.remaining_time == self.set_time:
self.clock_details = db.Clock_details()
self.clock_details.date = f"{date.today()}"
self.clock_details.start_clock = time.time()
self.get_goal()
self.data.start_time_first_clock = time.time()
self.data.start_time_this_clock = time.time()
self.clock_details.start_clock = time.time()
self.start_pause_button['text'] = "Pause"
self.start_pause_button['fg'] = "Red"
self.clock_ticking = True
Expand All @@ -167,10 +185,8 @@ def test_volume(self):
print(message)
command = shlex.split(f"say {message}")
subprocess.run(command)
print("Did you hear something? \n"
"If not, check your volume and sound system. \n"
"This is essential for getting notice from pomodoro when time's up. \n"
"Also, find PomodroTimer GUI window somewhere and interact there. :)")




class Meta():
Expand Down
98 changes: 98 additions & 0 deletions concentratetimer/ctimer_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import sqlite3
from sqlite3 import Error
from collections import namedtuple
from dataclasses import dataclass
from dataclasses import astuple


@dataclass(init=True, repr=True)
class Clock_details:
date: str = ""
clock_count: int = 0
start_clock: float = 12345.6
end_clock: float = 12345.6
end_break: float = 12345.7
task_title: str = "Task title TO BE IMPLEMENT"
task_description: str = "Task description to be set"
reached_bool: bool = False
reason: str = "N.A."


def db_add_clock_details(db_file, clock_instance):
# create a database connection
conn = create_connection(db_file)
with conn:
clock_id = create_clock_details(conn, astuple(clock_instance))
conn.close()
return clock_id


def create_table(db_file):
""" create a table from nothing
"""
try:
conn = sqlite3.connect(db_file)
c = conn.cursor()
# Create table
c.execute('''CREATE TABLE IF NOT EXISTS clock_details
(id integer PRIMARY KEY,
date text,
clock_count integer,
start_clock text,
end_clock text,
end_break text,
task_title text,
task_description text,
reached_bool text,
reason text )''')
conn.commit()
conn.close()
except Error as e:
print(e)


def create_connection(db_file):
""" create a database connection to the SQLite database
specified by db_file
:param db_file: database file
:return: Connection object or None
"""
conn = None
try:
conn = sqlite3.connect(db_file)
create_table(db_file)
except Error as e:
print(e)

return conn


def create_clock_details(conn, entry):
"""
Create a new clock detail entry into the clock_details table
:param conn: connection
:param entry:
:return: clock id
"""
# Insert a row of data
sql = '''INSERT INTO clock_details(date, clock_count, start_clock, end_clock, end_break, task_title,
task_description, reached_bool, reason) VALUES (?,?,?,?,?,?,?,?,?)'''
#TODO: add pause interval
cur = conn.cursor()
cur.execute(sql, entry)
return cur.lastrowid


def create_connection_new(db_file):
""" create a database connection to a SQLite database """
conn = None
try:
conn = sqlite3.connect(db_file)
print(sqlite3.version)
except Error as e:
print(e)
finally:
if conn:
conn.close()