-
Notifications
You must be signed in to change notification settings - Fork 14
/
main.py
234 lines (195 loc) · 7.8 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
import rumps
import time
import subprocess
import shlex
import sqlite3
import os
THINGS_SQLITE_PATH = "~/Library/Group Containers/JLMPQHK86H.com.culturedcode.ThingsMac/ThingsData-4R6L5/Things Database.thingsdatabase/main.sqlite"
def timez():
return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())
def get_things_today_tasks(index=0, complete_task=False):
conn = sqlite3.connect(os.path.expanduser(THINGS_SQLITE_PATH))
sql = (
"SELECT\n"
" TAG.title,\n"
" TASK.title,\n"
' "things:///show?id=" || TASK.uuid\n'
" FROM TMTask as TASK\n"
" LEFT JOIN TMTaskTag TAGS ON TAGS.tasks = TASK.uuid\n"
" LEFT JOIN TMTag TAG ON TAGS.tags = TAG.uuid\n"
" LEFT OUTER JOIN TMTask PROJECT ON TASK.project = PROJECT.uuid\n"
" LEFT OUTER JOIN TMArea AREA ON TASK.area = AREA.uuid\n"
" WHERE TASK.trashed = 0 AND TASK.status = 0 AND TASK.type = 0 AND TAG.title IS NOT NULL\n"
" AND TASK.start = 1\n"
" AND TASK.startdate is NOT NULL\n"
" ORDER BY TASK.todayIndex\n"
" LIMIT 100"
)
tasks = []
try:
for row in conn.execute(sql):
tasks.append(row)
except:
pass
conn.close()
return tasks
def process_tasks(list_of_tasks):
processed_tasks = {}
for task_tuple in list_of_tasks:
if task_tuple[0][-3:] == "min":
processed_tasks[task_tuple[1]] = (
int(task_tuple[0][:-3]),
task_tuple[2],
)
return processed_tasks
def hour_formatter(minutes):
if minutes // 60 > 0:
if spare_min := minutes % 60:
return f"{minutes // 60}h and {spare_min}min of work today!"
else:
return f"{minutes // 60}h of work today!"
else:
return f"{minutes}min of work today!"
class TimerApp(object):
def toggle_button(self, sender):
sender.state = not sender.state
def __init__(self, timer_interval=1):
self.timer = rumps.Timer(self.on_tick, 1)
self.timer.stop() # timer running when initialized
self.timer.count = 0
self.app = rumps.App("Timebox", "🥊")
self.interval = 60
self.current_things_task_url = None
self.start_pause_button = rumps.MenuItem(
title="Start Timer",
callback=lambda _: self.start_timer(_, self.interval),
key="s",
)
self.stop_button = rumps.MenuItem(title="Stop Timer", callback=None)
self.buttons = {}
self.buttons_callback = {}
for i in [5, 10, 15, 20, 25]:
title = str(i) + " Minutes"
callback = lambda _, j=i: self.set_mins(_, j, None)
self.buttons["btn_" + str(i)] = rumps.MenuItem(
title=title, callback=callback
)
self.buttons_callback[title] = callback
self.sync_button = rumps.MenuItem(
title="Sync", callback=lambda _: self.sync_data(), key="r"
)
self.sum_menu_item = rumps.MenuItem(
title="sum_total_time", callback=None
)
self.app.menu = [
self.start_pause_button,
self.sync_button,
None,
self.sum_menu_item,
# *self.things_buttons.values(),
None,
*self.buttons.values(),
None,
self.stop_button,
]
self.sync_data()
def sync_data(self):
for key, btn in self.buttons.items():
btn.set_callback(self.buttons_callback[btn.title])
self.things_tasks = get_things_today_tasks()
self.things_processed_tasks = process_tasks(self.things_tasks)
self.sum_of_tasks_scheduled = sum(
[x[0] for x in self.things_processed_tasks.values()]
)
self.app.menu[
"sum_total_time"
].title = f"{hour_formatter(self.sum_of_tasks_scheduled)}"
if hasattr(self, "things_buttons"):
prev_things_buttons = self.things_buttons
for title in prev_things_buttons.keys():
del self.app.menu[prev_things_buttons[title].title]
self.things_buttons = {
f"{title} → {time}min": rumps.MenuItem(
title=f"{title} → {time}min",
callback=lambda _, j=time, k=task_url: self.set_mins(_, j, k),
)
for title, (time, task_url) in self.things_processed_tasks.items()
}
for title, menu_item in reversed(self.things_buttons.items()):
self.app.menu.insert_after("sum_total_time", menu_item)
def run(self):
self.app.menu[
"sum_total_time"
].title = f"{hour_formatter(self.sum_of_tasks_scheduled)}"
self.app.run()
def set_mins(self, sender, interval, task_url):
for btn in [*self.things_buttons.values(), *self.buttons.values()]:
if sender.title == btn.title:
self.interval = interval * 60
cleaned_title = " ".join(sender.title.split()[:-2])
if task_url is not None:
self.menu_title = " → " + cleaned_title
self.current_things_task_url = task_url
else:
self.menu_title = ""
btn.state = True
elif sender.title != btn.title:
btn.state = False
def start_timer(self, sender, interval):
for btn in [*self.things_buttons.values(), *self.buttons.values()]:
btn.set_callback(None)
if sender.title.lower().startswith(("start", "continue")):
if sender.title == "Start Timer":
# reset timer & set stop time
self.timer.count = 0
self.timer.end = interval
# change title of MenuItem from 'Start timer' to 'Pause timer'
sender.title = "Pause Timer"
# lift off! start the timer
self.timer.start()
else: # 'Pause Timer'
sender.title = "Continue Timer"
self.timer.stop()
def on_tick(self, sender):
time_left = sender.end - sender.count
mins = time_left // 60 if time_left >= 0 else time_left // 60 + 1
secs = time_left % 60 if time_left >= 0 else (-1 * time_left) % 60
if mins == 0 and time_left < 0:
rumps.notification(
title="Timebox",
subtitle="Time is up! Take a break :)",
message="",
)
if self.current_things_task_url is not None:
# print("opening url", self.current_things_task_url)
subprocess.call(
shlex.split("open '" + self.current_things_task_url + "'")
)
self.current_things_task_url = None
self.stop_timer(sender)
self.stop_button.set_callback(None)
self.sync_data()
else:
self.stop_button.set_callback(self.stop_timer)
self.app.title = "{:2d}:{:02d} {}".format(
mins, secs, getattr(self, "menu_title", "")
)
sender.count += 1
def stop_timer(self, sender=None):
self.timer.stop()
self.timer.count = 0
self.app.title = "🥊"
self.stop_button.set_callback(None)
for key, btn in self.buttons.items():
btn.set_callback(self.buttons_callback[btn.title])
for (title, btn) in self.things_buttons.items():
btn.set_callback(
lambda _: self.set_mins(
_, self.things_processed_tasks[title], None
)
)
self.start_pause_button.title = "Start Timer"
self.sync_data()
if __name__ == "__main__":
app = TimerApp(timer_interval=1)
app.run()