nowfocus 0.5.6__py3-none-any.whl → 0.5.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nowfocus/__main__.py +61 -35
- nowfocus/conf.py +2 -1
- nowfocus/connectors/taskwarrior.py +7 -0
- nowfocus/connectors/vikunja.py +9 -51
- nowfocus/desktop-extras/nowfocus.desktop +1 -1
- nowfocus/error_dialog.py +69 -0
- nowfocus/install.py +0 -1
- nowfocus/new_task_dialog.py +10 -6
- nowfocus/session_edit_dialog.py +2 -4
- nowfocus/settings.py +45 -33
- nowfocus/task_window.py +3 -3
- nowfocus/upgrade.py +106 -0
- nowfocus/utils.py +144 -137
- {nowfocus-0.5.6.dist-info → nowfocus-0.5.9.dist-info}/METADATA +3 -8
- {nowfocus-0.5.6.dist-info → nowfocus-0.5.9.dist-info}/RECORD +19 -18
- {nowfocus-0.5.6.dist-info → nowfocus-0.5.9.dist-info}/WHEEL +1 -1
- nowfocus/version_migrator.py +0 -20
- {nowfocus-0.5.6.dist-info → nowfocus-0.5.9.dist-info}/entry_points.txt +0 -0
- {nowfocus-0.5.6.dist-info → nowfocus-0.5.9.dist-info}/licenses/LICENSE +0 -0
- {nowfocus-0.5.6.dist-info → nowfocus-0.5.9.dist-info}/top_level.txt +0 -0
nowfocus/utils.py
CHANGED
|
@@ -7,7 +7,6 @@ from datetime import datetime, timezone, timedelta
|
|
|
7
7
|
from dateutil.relativedelta import relativedelta
|
|
8
8
|
import copy
|
|
9
9
|
import threading
|
|
10
|
-
|
|
11
10
|
import sqlite3
|
|
12
11
|
from contextlib import closing
|
|
13
12
|
from pathlib import Path
|
|
@@ -27,14 +26,16 @@ import traceback
|
|
|
27
26
|
import conf
|
|
28
27
|
notify.init(conf.app_name)
|
|
29
28
|
|
|
29
|
+
from error_dialog import ErrorDialog
|
|
30
|
+
|
|
30
31
|
lists = {}
|
|
31
32
|
|
|
32
33
|
|
|
33
|
-
def dbg(*data, s="", l=2, e=None,
|
|
34
|
+
def dbg(*data, s="", l=2, e=None, notification=None):
|
|
34
35
|
''' Any number of positional args optionally
|
|
35
36
|
l: level {-1: Default output, 0:Error, 1:Warning, 2:Info, 3:Details}
|
|
36
37
|
s: system (Debuggable systems: 'taskwindow','signals','todoloading','user_settings', 'targets', 'performance')
|
|
37
|
-
|
|
38
|
+
notification: Show a notification with the content of notification.
|
|
38
39
|
e (Exception object) traceback will be printed
|
|
39
40
|
|
|
40
41
|
'''
|
|
@@ -47,8 +48,8 @@ def dbg(*data, s="", l=2, e=None, notify=None):
|
|
|
47
48
|
|
|
48
49
|
if "all" in conf.debug_systems or system in conf.debug_systems or level <= conf.debug_level:
|
|
49
50
|
|
|
50
|
-
if
|
|
51
|
-
notify.Notification.new(conf.app_name+" "+levels[level], str(
|
|
51
|
+
if notification:
|
|
52
|
+
notify.Notification.new(conf.app_name+" "+levels[level], str(notification), None).show()
|
|
52
53
|
|
|
53
54
|
filter(None,data)
|
|
54
55
|
if len(data) == 1:
|
|
@@ -67,8 +68,24 @@ def dbg(*data, s="", l=2, e=None, notify=None):
|
|
|
67
68
|
# pretty_print(data)
|
|
68
69
|
|
|
69
70
|
if e and isinstance(e,Exception):
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
|
|
72
|
+
error_report = str(e) + '\n' + traceback.format_exc()
|
|
73
|
+
|
|
74
|
+
print(error_report)
|
|
75
|
+
|
|
76
|
+
if data:
|
|
77
|
+
error_report = json.dumps(data,indent=2) + error_report
|
|
78
|
+
|
|
79
|
+
print("show ErrorDialog")
|
|
80
|
+
error_dialog_inst = ErrorDialog(None, error_report)
|
|
81
|
+
error_dialog_inst.show_all()
|
|
82
|
+
|
|
83
|
+
# if level == 0:
|
|
84
|
+
# with open(conf.error_log_file,'a') as error_log:
|
|
85
|
+
# error_log.write(str(e))
|
|
86
|
+
# error_log.write(traceback.format_exc())
|
|
87
|
+
|
|
88
|
+
|
|
72
89
|
|
|
73
90
|
def error_notice(title, details = None, e = None):
|
|
74
91
|
print('ERROR',title,details,e)
|
|
@@ -135,7 +152,7 @@ def sec_to_time(sec):
|
|
|
135
152
|
try:
|
|
136
153
|
int(sec)
|
|
137
154
|
except Exception as e:
|
|
138
|
-
|
|
155
|
+
dbg("sec to time error", e=e, l=0)
|
|
139
156
|
sec = 0
|
|
140
157
|
|
|
141
158
|
time = str("{:02d}".format(int(sec // 3600))) + ':' + str("{:02d}".format(int((sec % 3600) // 60))) + ':' + str("{:02d}".format(int(sec % 60)))
|
|
@@ -170,7 +187,7 @@ def validate_start_time_str(start_time_string):
|
|
|
170
187
|
return datetime.strptime(start_time_string,'%Y-%m-%d %H:%M:%S')
|
|
171
188
|
|
|
172
189
|
except Exception as e:
|
|
173
|
-
|
|
190
|
+
dbg('Incorrect Start Time Format', start_time_string+" does no match %Y-%m-%d %H:%M:%S", e=e, l=0)
|
|
174
191
|
return False
|
|
175
192
|
|
|
176
193
|
|
|
@@ -186,7 +203,7 @@ def open_todo(w=None, i=None, item_type = 'tasks'):
|
|
|
186
203
|
|
|
187
204
|
except Exception as e:
|
|
188
205
|
# error_notice('Bonk', "error with "+ c['type']+ " open function ")
|
|
189
|
-
dbg('open_todo
|
|
206
|
+
dbg('open_todo exception, falling back to get_connector_openable ',e=e ,s=todo['type'],l=1)
|
|
190
207
|
|
|
191
208
|
get_connector_openable(None,todo)
|
|
192
209
|
|
|
@@ -267,21 +284,21 @@ def extended_label(i):
|
|
|
267
284
|
o = ' > '.join(l)
|
|
268
285
|
return o
|
|
269
286
|
|
|
270
|
-
|
|
271
|
-
def lists_cache(new_lists = None):
|
|
272
|
-
'''Set or get a dict of (all) lists.
|
|
287
|
+
|
|
288
|
+
def lists_cache(new_lists = None, reset = False):
|
|
289
|
+
'''Set or get a dict of (all) lists. If new_lists is supplied it will exclusively use that (until it is replaced or the global lists var is emptied) This is useful (because it can be used wih input when the values are not yet available in the databse) but wonky. '''
|
|
290
|
+
|
|
273
291
|
global lists
|
|
274
292
|
|
|
275
293
|
if(new_lists):
|
|
276
294
|
lists = new_lists
|
|
277
|
-
# TODO: add
|
|
295
|
+
# TODO: add a param to append to the existing lists rather than overwriting...
|
|
278
296
|
|
|
279
|
-
elif
|
|
280
|
-
lists = db_query('SELECT * FROM lists WHERE status = 1 ORDER BY extended_label DESC',None, 'id')
|
|
297
|
+
elif reset or lists == {}:
|
|
298
|
+
lists = db_query('SELECT * FROM lists WHERE status = 1 ORDER BY extended_label DESC',None, 'id')
|
|
281
299
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
lists[l['id']]['data'] = json.loads(l['data'])
|
|
300
|
+
for id, l in lists.items():
|
|
301
|
+
lists[l['id']] = proc_db_item(l,'lists')
|
|
285
302
|
|
|
286
303
|
return lists
|
|
287
304
|
|
|
@@ -336,7 +353,7 @@ def db_query(sql,parameters=None,key=None,error_handling=1):
|
|
|
336
353
|
return result
|
|
337
354
|
|
|
338
355
|
except Exception as e:
|
|
339
|
-
dbg(
|
|
356
|
+
dbg("sql",sql,'parameters',parameters,s="db",l=0,e=e)
|
|
340
357
|
if error_handling > 0:
|
|
341
358
|
error_notice("database error",str(e))
|
|
342
359
|
if error_handling > 1:
|
|
@@ -347,88 +364,6 @@ def db_query(sql,parameters=None,key=None,error_handling=1):
|
|
|
347
364
|
return []
|
|
348
365
|
|
|
349
366
|
|
|
350
|
-
def db_schema_update():
|
|
351
|
-
|
|
352
|
-
try:
|
|
353
|
-
db_schema_version = float(db_query("SELECT field, value FROM system WHERE field = 'db_schema_version' ",error_handling=2)[0]['value'])
|
|
354
|
-
except Exception as e:
|
|
355
|
-
print("Updating db_schema_version to 0.2")
|
|
356
|
-
|
|
357
|
-
db_query("CREATE TABLE system (field TEXT PRIMARY KEY NOT NULL, value TEXT)")
|
|
358
|
-
db_query("REPLACE INTO system(field, value) VALUES('db_schema_version', '0.2')")
|
|
359
|
-
|
|
360
|
-
db_schema_version = float(db_query("SELECT field, value FROM system WHERE field = 'db_schema_version' ")[0]['value'])
|
|
361
|
-
|
|
362
|
-
db_query("ALTER TABLE lists ADD COLUMN status INTEGER DEFAULT 1")
|
|
363
|
-
db_query("ALTER TABLE tasks ADD COLUMN status INTEGER DEFAULT 1")
|
|
364
|
-
|
|
365
|
-
db_query("ALTER TABLE lists ADD COLUMN extended_label TEXT")
|
|
366
|
-
db_query("ALTER TABLE tasks ADD COLUMN extended_label TEXT")
|
|
367
|
-
|
|
368
|
-
db_query("ALTER TABLE sessions ADD COLUMN extended_label TEXT")
|
|
369
|
-
|
|
370
|
-
# Since these column are just a cache, replace instead of copying columns
|
|
371
|
-
db_query("ALTER TABLE tasks DROP COLUMN priority")
|
|
372
|
-
db_query("ALTER TABLE tasks DROP COLUMN data")
|
|
373
|
-
db_query("ALTER TABLE lists DROP COLUMN priority")
|
|
374
|
-
db_query("ALTER TABLE lists DROP COLUMN data")
|
|
375
|
-
|
|
376
|
-
db_query("ALTER TABLE lists ADD COLUMN priority INTEGER DEFAULT 0")
|
|
377
|
-
db_query("ALTER TABLE lists ADD COLUMN data TEXT DEFAULT '{}'")
|
|
378
|
-
db_query("ALTER TABLE tasks ADD COLUMN priority INTEGER DEFAULT 0")
|
|
379
|
-
db_query("ALTER TABLE tasks ADD COLUMN data TEXT DEFAULT '{}'")
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
if db_schema_version == 0.2:
|
|
383
|
-
|
|
384
|
-
db_query("ALTER TABLE lists DROP COLUMN status")
|
|
385
|
-
db_query("ALTER TABLE tasks DROP COLUMN status")
|
|
386
|
-
|
|
387
|
-
db_query("ALTER TABLE lists ADD COLUMN status INTEGER DEFAULT 1")
|
|
388
|
-
db_query("ALTER TABLE tasks ADD COLUMN status INTEGER DEFAULT 1")
|
|
389
|
-
|
|
390
|
-
db_query("REPLACE INTO system(field, value) VALUES('db_schema_version', '0.3')")
|
|
391
|
-
|
|
392
|
-
db_schema_version = 0.3
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
if db_schema_version == 0.3:
|
|
396
|
-
db_query("ALTER TABLE sessions ADD COLUMN timetracker TEXT")
|
|
397
|
-
db_query("ALTER TABLE sessions ADD COLUMN notes TEXT")
|
|
398
|
-
db_query("REPLACE INTO system(field, value) VALUES('db_schema_version', '0.4')")
|
|
399
|
-
print('adding timetracker column to session table')
|
|
400
|
-
|
|
401
|
-
for todolist_id, todo in conf.user['todolists'].items():
|
|
402
|
-
db_query("UPDATE sessions SET timetracker = ? WHERE todolist = ?",(todo['timetracker'],todolist_id) )
|
|
403
|
-
|
|
404
|
-
db_schema_version = 0.4
|
|
405
|
-
|
|
406
|
-
if db_schema_version == 0.4:
|
|
407
|
-
print('Adding priority column to session table')
|
|
408
|
-
|
|
409
|
-
db_query("ALTER TABLE sessions ADD COLUMN priority INTEGER DEFAULT 0")
|
|
410
|
-
|
|
411
|
-
for session in db_query("SELECT DISTINCT task_id, extended_label FROM sessions"):
|
|
412
|
-
t = db_get_item_by_id(session['task_id'],dgb_error_level_for_failure=3)
|
|
413
|
-
if t and t['priority'] > 0:
|
|
414
|
-
print("setting",session['extended_label']," session priority to ",t['priority'] )
|
|
415
|
-
|
|
416
|
-
db_query("UPDATE sessions SET priority = ? WHERE task_id = ?",(t['priority'],session['task_id']))
|
|
417
|
-
|
|
418
|
-
print("Total hours priority sessions",round(divide(db_query("SELECT SUM(duration) as total FROM sessions WHERE priority > 0")[0]['total'],3600),2))
|
|
419
|
-
db_query("REPLACE INTO system(field, value) VALUES('db_schema_version', '0.5')")
|
|
420
|
-
|
|
421
|
-
db_schema_version = 0.5
|
|
422
|
-
|
|
423
|
-
# if db_schema_version == 0.5:
|
|
424
|
-
# db_query("ALTER TABLE tasks ADD COLUMN tags TEXT DEFAULT '{}'")
|
|
425
|
-
# db_query("REPLACE INTO system(field, value) VALUES('db_schema_version', '0.5')")
|
|
426
|
-
# db_schema_version = 0.6
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
dbg('db_schema_version', db_schema_version,s='db')
|
|
430
|
-
|
|
431
|
-
|
|
432
367
|
def reindex(t=None):
|
|
433
368
|
if t:
|
|
434
369
|
thread = threading.Thread(target=reindex_one,args=(t,))
|
|
@@ -447,8 +382,9 @@ def reindex_all():
|
|
|
447
382
|
for tid, t in get_timetarget_priority_tasks().items():
|
|
448
383
|
db_query("UPDATE taskindex set priority = ? WHERE id = ?",(t['priority'],t['id']))
|
|
449
384
|
|
|
450
|
-
|
|
451
|
-
|
|
385
|
+
|
|
386
|
+
set_system_db_value('taskindex_update_time', now().strftime("%Y-%m-%d %H:%M:%S"))
|
|
387
|
+
|
|
452
388
|
timeit()
|
|
453
389
|
|
|
454
390
|
return True
|
|
@@ -464,16 +400,19 @@ def reindex_one(t):
|
|
|
464
400
|
|
|
465
401
|
db_query("INSERT INTO taskindex(id, extended_label, priority, status) SELECT id, extended_label, ?, status FROM tasks WHERE id = ? ",(time_target_priority(t),t['id'],))
|
|
466
402
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
403
|
+
dbg("reindexed",t['label'])
|
|
404
|
+
|
|
405
|
+
set_system_db_value('taskindex_update_time', now().strftime("%Y-%m-%d %H:%M:%S"))
|
|
406
|
+
|
|
470
407
|
return True
|
|
471
408
|
|
|
472
409
|
|
|
473
410
|
def taskindex_updated_time():
|
|
474
411
|
''' returns system db taskindex_update_time string formatted as %Y-%m-%d %H:%M:%S '''
|
|
475
|
-
update_time = db_query("SELECT value FROM system WHERE field = 'taskindex_update_time'")[0]['value']
|
|
476
412
|
|
|
413
|
+
update_time = get_system_db_value('taskindex_update_time')
|
|
414
|
+
|
|
415
|
+
|
|
477
416
|
# print('taskindex_updated_time',update_time)
|
|
478
417
|
# return datetime.strptime(update_time,'%Y-%m-%d %H:%M:%S')
|
|
479
418
|
return update_time
|
|
@@ -631,7 +570,7 @@ def db_set_todolist(todolist_id,lists,tasks):
|
|
|
631
570
|
insert_tasks[id] = db_prepare_item(i,'tasks')
|
|
632
571
|
|
|
633
572
|
# Clear incomplete lists cache
|
|
634
|
-
lists_cache(
|
|
573
|
+
lists_cache(reset=True)
|
|
635
574
|
|
|
636
575
|
# for testing
|
|
637
576
|
# insert_tasks = {'3':insert_tasks['3'],'294':insert_tasks['294']}
|
|
@@ -709,13 +648,17 @@ def db_cleanup(widget = None):
|
|
|
709
648
|
|
|
710
649
|
# exit()
|
|
711
650
|
|
|
712
|
-
def db_get_item_by_id(id,table = 'tasks',dgb_error_level_for_failure=0):
|
|
651
|
+
def db_get_item_by_id(id, table = 'tasks',dgb_error_level_for_failure=0):
|
|
713
652
|
|
|
714
653
|
if table in ['task','list']:
|
|
715
654
|
table = table+'s'
|
|
716
655
|
if table not in ['tasks','lists']:
|
|
717
656
|
dbg('bad table "'+str(table)+'" passed to db_get_item_by_id',id,l=0)
|
|
718
657
|
return {}
|
|
658
|
+
|
|
659
|
+
# in case an item dict was passed instead of an id
|
|
660
|
+
if isinstance(id, dict):
|
|
661
|
+
return id
|
|
719
662
|
|
|
720
663
|
try:
|
|
721
664
|
data = db_query("SELECT * FROM "+table+" WHERE id = ?",(id,))
|
|
@@ -727,7 +670,9 @@ def db_get_item_by_id(id,table = 'tasks',dgb_error_level_for_failure=0):
|
|
|
727
670
|
return {}
|
|
728
671
|
|
|
729
672
|
except Exception as e:
|
|
730
|
-
dbg('db_get_item_by_id failed',e,l=dgb_error_level_for_failure)
|
|
673
|
+
dbg('db_get_item_by_id failed',e=e ,l=dgb_error_level_for_failure)
|
|
674
|
+
return {}
|
|
675
|
+
|
|
731
676
|
|
|
732
677
|
|
|
733
678
|
def get_todo_by_id(todo_or_todo_id = None):
|
|
@@ -777,8 +722,12 @@ def db_save_session(session):
|
|
|
777
722
|
'priority': "0",
|
|
778
723
|
}
|
|
779
724
|
|
|
725
|
+
# dbg('task in db_save_session', session['task'],l=3)
|
|
726
|
+
|
|
780
727
|
if 'priority' in session['task']:
|
|
781
|
-
prepared_session['priority']
|
|
728
|
+
prepared_session['priority'] = str(session['task']['priority'])
|
|
729
|
+
|
|
730
|
+
dbg('db_save_session data:',prepared_session)
|
|
782
731
|
|
|
783
732
|
db_query("INSERT INTO sessions(start_time, duration, task_id, parent_id, todolist, extended_label,timetracker, notes, priority) VALUES(:start_time, :duration, :task_id, :parent_id, :todolist, :extended_label, :timetracker, :notes, :priority )",prepared_session)
|
|
784
733
|
|
|
@@ -865,7 +814,7 @@ def db_set_session_cache(s):
|
|
|
865
814
|
''' Add active session to system db table. Not to be confused with db_save_session '''
|
|
866
815
|
db_session = copy.deepcopy(s)
|
|
867
816
|
db_session['start_time'] = db_session['start_time'].strftime("%Y-%m-%d %H:%M:%S.%f%z")
|
|
868
|
-
|
|
817
|
+
set_system_db_value('session', json.dumps(db_session))
|
|
869
818
|
|
|
870
819
|
|
|
871
820
|
def get_total_time(id, category = 'tasks', start_time = None, end_time = None, get_minutes = None):
|
|
@@ -1057,17 +1006,17 @@ def refresh_todolist(todo, catch_errors = False):
|
|
|
1057
1006
|
''' Refresh a single todo. runs db_set_todolist and returns todos. Exceptions must be handled my caller '''
|
|
1058
1007
|
|
|
1059
1008
|
try:
|
|
1060
|
-
dbg('Refreshing '+todo['label'],l
|
|
1009
|
+
dbg('Refreshing '+todo['label'],l=2)
|
|
1061
1010
|
|
|
1062
1011
|
todos = conf.todo_connectors[todo['type']].get_todos(todo)
|
|
1063
1012
|
|
|
1064
|
-
dbg('
|
|
1013
|
+
dbg('Refreshing '+todo['label'],l=-1)
|
|
1065
1014
|
|
|
1066
1015
|
db_set_todolist(todo['id'],todos['lists'],todos['tasks'])
|
|
1067
1016
|
|
|
1068
1017
|
except Exception as e:
|
|
1069
1018
|
if catch_errors:
|
|
1070
|
-
|
|
1019
|
+
dbg(notification='Error Loading '+todo['label']+' i refresh_todolist',e=e,l=0)
|
|
1071
1020
|
todos = {'lists': {}, 'tasks':{}}
|
|
1072
1021
|
|
|
1073
1022
|
else:
|
|
@@ -1088,13 +1037,13 @@ def handle_todo_read_error(todo_conf,e):
|
|
|
1088
1037
|
if isinstance(e, (FileExistsError, FileNotFoundError, PermissionError)):
|
|
1089
1038
|
handle_todo_file_access_error(todo_conf,e)
|
|
1090
1039
|
|
|
1091
|
-
dbg(todo_conf['label']+ " Access Error",e,l=0
|
|
1040
|
+
dbg(notification=todo_conf['label']+ " Access Error",e=e ,l=0)
|
|
1092
1041
|
|
|
1093
1042
|
|
|
1094
1043
|
def handle_todo_file_read_error(todo_conf,e):
|
|
1095
1044
|
conf.user['todolists'][todo_conf['id']]['status'] = False
|
|
1096
1045
|
save_user_settings()
|
|
1097
|
-
dbg(todo_conf['label']+ " Deactivated",e,l=-1
|
|
1046
|
+
dbg(notification=todo_conf['label']+ " Deactivated",e=e ,l=-1)
|
|
1098
1047
|
|
|
1099
1048
|
|
|
1100
1049
|
def get_todolists(use_db_cache = False):
|
|
@@ -1125,12 +1074,12 @@ def get_todolists(use_db_cache = False):
|
|
|
1125
1074
|
if conf.debug_level == 3 or 'todoloading' in conf.debug_systems or todo['type'] in conf.debug_systems :
|
|
1126
1075
|
raise e
|
|
1127
1076
|
|
|
1128
|
-
|
|
1077
|
+
dbg(notification='Error refreshing '+todo['label'],e=e)
|
|
1129
1078
|
|
|
1130
1079
|
try:
|
|
1131
1080
|
todos = db_get_todolist(todo['id'])
|
|
1132
1081
|
except Exception as e:
|
|
1133
|
-
|
|
1082
|
+
dbg('Also Failed to load '+todo['label']+' From cache' ,e=e,l=0)
|
|
1134
1083
|
todos = {'lists': {}, 'tasks':{}}
|
|
1135
1084
|
|
|
1136
1085
|
tasks.update(todos['tasks'])
|
|
@@ -1147,14 +1096,79 @@ def get_todolists(use_db_cache = False):
|
|
|
1147
1096
|
return o
|
|
1148
1097
|
|
|
1149
1098
|
|
|
1099
|
+
def get_system_db_value(field, json = False):
|
|
1100
|
+
try:
|
|
1101
|
+
o = db_query("SELECT value FROM system WHERE field = ? ",(field,))
|
|
1102
|
+
if o:
|
|
1103
|
+
o = o[0]['value']
|
|
1104
|
+
else:
|
|
1105
|
+
dbg('no system_db_value for', field, l=1)
|
|
1106
|
+
|
|
1107
|
+
if json:
|
|
1108
|
+
o = json.loads(o)
|
|
1109
|
+
return o
|
|
1110
|
+
except Exception as e:
|
|
1111
|
+
dbg("Error getting",field, 'from system db',e=e ,l=0)
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
def set_system_db_value(field, value, json = False):
|
|
1115
|
+
try:
|
|
1116
|
+
if json:
|
|
1117
|
+
value = json.dumps(value)
|
|
1118
|
+
|
|
1119
|
+
db_query("REPLACE INTO system(field, value) VALUES(:field, :value)", {'field':field,'value':value})
|
|
1120
|
+
|
|
1121
|
+
except Exception as e:
|
|
1122
|
+
dbg("Error setting", field, value, 'in system db',e=e ,l=0)
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
def get_session_from_system_db():
|
|
1126
|
+
try:
|
|
1127
|
+
db_session = db_query("SELECT value FROM system WHERE field = 'session'")
|
|
1128
|
+
|
|
1129
|
+
if db_session:
|
|
1130
|
+
s = json.loads(db_session[0]['value'])
|
|
1131
|
+
s['start_time'] = datetime.strptime(s['start_time'],'%Y-%m-%d %H:%M:%S.%f')
|
|
1132
|
+
return s
|
|
1133
|
+
except Exception as e:
|
|
1134
|
+
dbg("Error in get_session_from_system_db session",e=e ,l=1)
|
|
1135
|
+
|
|
1136
|
+
|
|
1150
1137
|
def get_most_recent_list(session = None):
|
|
1138
|
+
''' returns a list object '''
|
|
1139
|
+
lists = lists_cache()
|
|
1140
|
+
# print(lists.keys())
|
|
1141
|
+
|
|
1142
|
+
try:
|
|
1143
|
+
return lists[session['task']['parent_id']]
|
|
1144
|
+
|
|
1145
|
+
except Exception as e:
|
|
1146
|
+
pass
|
|
1147
|
+
|
|
1148
|
+
try:
|
|
1149
|
+
return lists[get_session_from_system_db()['task']['parent_id']]
|
|
1150
|
+
|
|
1151
|
+
except Exception as e:
|
|
1152
|
+
pass
|
|
1153
|
+
|
|
1154
|
+
try:
|
|
1155
|
+
return lists[db_query("SELECT parent_id FROM sessions WHERE parent_id IN (SELECT id FROM lists WHERE status = 1) ORDER BY sessions.start_time DESC LIMIT 1")[0]['parent_id']]
|
|
1151
1156
|
|
|
1152
|
-
|
|
1153
|
-
|
|
1157
|
+
except Exception as e:
|
|
1158
|
+
return lists.items()[0]
|
|
1159
|
+
|
|
1160
|
+
|
|
1161
|
+
|
|
1162
|
+
def get_default_list_for_new_tasks():
|
|
1163
|
+
|
|
1164
|
+
if conf.user['default_list_for_new_tasks'] == 'List that was last added to':
|
|
1165
|
+
|
|
1166
|
+
id = get_system_db_value('last_added_to_list_id')
|
|
1167
|
+
if id and id in lists_cache():
|
|
1168
|
+
return lists_cache()[id]
|
|
1154
1169
|
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
return last_session[0]['parent_id']
|
|
1170
|
+
# if conf.user['default_list_for_new_tasks'] == 'Most recently used list':
|
|
1171
|
+
return get_most_recent_list()
|
|
1158
1172
|
|
|
1159
1173
|
|
|
1160
1174
|
def choose_from_lists(callback, selected_list_id = None, session = None, accepts_tasks = True, show_todolist_headers = True, truncate_labels_to_chars = 100):
|
|
@@ -1175,25 +1189,20 @@ def choose_from_lists(callback, selected_list_id = None, session = None, accepts
|
|
|
1175
1189
|
# scrolled_window.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
|
|
1176
1190
|
scrolled_window.add(box)
|
|
1177
1191
|
|
|
1178
|
-
todolist = None
|
|
1179
|
-
|
|
1180
|
-
conditions = " "
|
|
1181
|
-
|
|
1182
|
-
# if skip_top_level_lists:
|
|
1183
|
-
# conditions += " AND parent_label IS NOT NULL "
|
|
1184
|
-
|
|
1185
|
-
lists = db_query("SELECT lists.*, (SELECT start_time FROM sessions WHERE todolist = lists.todolist ORDER BY start_time DESC LIMIT 1 ) as last_session_on_todo FROM lists WHERE status = '1' "+conditions+" ORDER BY last_session_on_todo DESC, CASE WHEN parent_id IS NULL THEN 1 ELSE 2 END, extended_label ASC ", None, 'id')
|
|
1192
|
+
lists = db_query("SELECT lists.*, (SELECT start_time FROM sessions WHERE todolist = lists.todolist ORDER BY start_time DESC LIMIT 1 ) as last_session_on_todo FROM lists WHERE status = '1' ORDER BY last_session_on_todo DESC, CASE WHEN parent_id IS NULL THEN 1 ELSE 2 END, extended_label ASC ", None, 'id')
|
|
1186
1193
|
|
|
1187
1194
|
r_button = None
|
|
1188
1195
|
todolist_id = None
|
|
1189
1196
|
|
|
1190
1197
|
for id, l in lists.items():
|
|
1191
1198
|
try:
|
|
1192
|
-
l
|
|
1199
|
+
l = proc_db_item(l)
|
|
1193
1200
|
if len(l['label']) > truncate_labels_to_chars:
|
|
1194
1201
|
l['label'] = l['label'][:truncate_labels_to_chars] + '…'
|
|
1202
|
+
|
|
1203
|
+
nested_list_count = l['extended_label'].count(' > ')
|
|
1195
1204
|
|
|
1196
|
-
label = f'{" · " *
|
|
1205
|
+
label = f'{" · " * nested_list_count}' + GLib.markup_escape_text(l['label'])
|
|
1197
1206
|
|
|
1198
1207
|
if todolist_id != l['todolist']:
|
|
1199
1208
|
todolist_id = l['todolist']
|
|
@@ -1210,14 +1219,12 @@ def choose_from_lists(callback, selected_list_id = None, session = None, accepts
|
|
|
1210
1219
|
|
|
1211
1220
|
if accepts_tasks and l['data']['accepts_tasks'] == False:
|
|
1212
1221
|
label_widget.set_markup(' '+label)
|
|
1213
|
-
|
|
1214
1222
|
box.add(label_widget)
|
|
1215
1223
|
|
|
1216
1224
|
else:
|
|
1217
1225
|
r_button = Gtk.RadioButton(group=r_button)
|
|
1218
1226
|
r_button.add(label_widget)
|
|
1219
1227
|
|
|
1220
|
-
|
|
1221
1228
|
if l['id'] == selected_list_id:
|
|
1222
1229
|
r_button.set_active(True)
|
|
1223
1230
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nowfocus
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.9
|
|
4
4
|
Summary: nowfocus: the open source task-tracking self-control panel.
|
|
5
5
|
Author: AltruistEnterprises
|
|
6
6
|
Project-URL: Homepage, https://www.nowfocus.org
|
|
@@ -58,7 +58,7 @@ nowfocus is a clean, keyboard-driven time management dashboard that flexibly con
|
|
|
58
58
|
- Task prioritization
|
|
59
59
|
- Infinitely nestable lists
|
|
60
60
|
- Pomodoro timer
|
|
61
|
-
- Time targets: set a minimum or maximum time for any task or list of tasks and get reminded to follow
|
|
61
|
+
- Time targets: set a minimum or maximum time for any task or list of tasks and get reminded to follow-through
|
|
62
62
|
- Randomness interrupt bell (optional) to keep you on track with tracking your time
|
|
63
63
|
- Keyboard-driven interface
|
|
64
64
|
- Offline to-do list cache
|
|
@@ -121,12 +121,7 @@ nowfocus is a clean, keyboard-driven time management dashboard that flexibly con
|
|
|
121
121
|
```
|
|
122
122
|
bash -c "echo 'open_task_window' > /tmp/nowfocus-pipe"
|
|
123
123
|
```
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
3. Add the following command to your startup applications:
|
|
127
|
-
```
|
|
128
|
-
nowfocus --force
|
|
129
|
-
```
|
|
124
|
+
|
|
130
125
|
|
|
131
126
|
|
|
132
127
|
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
nowfocus/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
2
|
-
nowfocus/__main__.py,sha256=
|
|
3
|
-
nowfocus/conf.py,sha256=
|
|
2
|
+
nowfocus/__main__.py,sha256=BDNlrtNuQWY4-PxVHKJE1yIyeMTZDQni0OUnWF9uOuk,34069
|
|
3
|
+
nowfocus/conf.py,sha256=fBKbM57teU4-LGcX-hmgnjH5TaP5hwQ7YhmtugDNx74,6804
|
|
4
|
+
nowfocus/error_dialog.py,sha256=DMMGoaqMmcTD6YZT5X6exocEs4sTveCYu03Qgc9fVP8,1799
|
|
4
5
|
nowfocus/example-todo.txt,sha256=o-ZRNiTlSGFbTK9jpdDIi07qHBrpvP0JhBZSk0VlpQU,246
|
|
5
|
-
nowfocus/install.py,sha256=
|
|
6
|
-
nowfocus/new_task_dialog.py,sha256=
|
|
7
|
-
nowfocus/session_edit_dialog.py,sha256=
|
|
6
|
+
nowfocus/install.py,sha256=gzjDzqUFYRP1dS_zA_MKrTZWTAB1bYqcxjRw5mBn1aQ,3039
|
|
7
|
+
nowfocus/new_task_dialog.py,sha256=TtN0Cr2x3uZ62NvXrxeE1_oVqjQM5OCUY104-TSb-6A,4474
|
|
8
|
+
nowfocus/session_edit_dialog.py,sha256=7gayBGyZc2JlVMnmibVfHt6HL52CXErSoDDgbnaE6Zs,6858
|
|
8
9
|
nowfocus/session_options.py,sha256=mOnyEM3-usKgVvBhESY0TNBcy4FTG-AHP6ETMgB1fQ4,5071
|
|
9
10
|
nowfocus/sessions.csv,sha256=kYpr06yQg_J86NQ4AiYw4RnQchcw3ouPKVYa1lYDUNo,39
|
|
10
|
-
nowfocus/settings.py,sha256=
|
|
11
|
+
nowfocus/settings.py,sha256=rb4kotRJLbNgPSMaN1EfhJzJ0F4xBCI_MZf30SlMazs,35796
|
|
11
12
|
nowfocus/styles.css,sha256=PG1SrLkwSSay8M2VKeRcE0UdK54ndsEDFnRLRkmP-9M,510
|
|
12
|
-
nowfocus/task_window.py,sha256=
|
|
13
|
+
nowfocus/task_window.py,sha256=zcR1kk2f_vtwXiIm4PY_sKZ5wsfhtEfg9Hl8X9H0TRM,28883
|
|
14
|
+
nowfocus/upgrade.py,sha256=ckCsXnAO8goLNZLvBWmhFQeM0sDJ_bsn5EAV3vsLiwY,3600
|
|
13
15
|
nowfocus/user_idle_time.py,sha256=I44Ip-iGGzWAiHnM2_06jNqhCne9y1SbvcBI-nYBolU,2365
|
|
14
|
-
nowfocus/utils.py,sha256=
|
|
15
|
-
nowfocus/version_migrator.py,sha256=q8T1C8-DLOwUQUM5IPcMjPbVbsLTO4VsqADlAAXd9gw,628
|
|
16
|
+
nowfocus/utils.py,sha256=s187QkyJrD8lrlsFLW1OV9TV0tK9-eOi_gVwvn6W86U,49520
|
|
16
17
|
nowfocus/connectors/activitywatch.py,sha256=QbkOmjIOiVwccWc2xhhePd0Abww5vEiVpCNjeqOyYGg,921
|
|
17
18
|
nowfocus/connectors/caldav.py,sha256=PeM_9yJC8W17L8Y5AyS75o6GfzTrPoMYKIvetND8T78,5089
|
|
18
19
|
nowfocus/connectors/csv.py,sha256=FwMpHM5lPIT90HKBCQUncpaW7zqFjlHjMwKR0-XWg-4,821
|
|
19
20
|
nowfocus/connectors/psc_timetracker.py,sha256=gyx0bQkOC467lkF7tTcoKD451u3WPEEBjAvNeZc6W5s,9767
|
|
20
|
-
nowfocus/connectors/taskwarrior.py,sha256=
|
|
21
|
+
nowfocus/connectors/taskwarrior.py,sha256=hDhbiP7tiIzK1QJCSlcA3msrsSCA6MQtJ6TO1VHsDLM,3423
|
|
21
22
|
nowfocus/connectors/timewarrior.py,sha256=0Hra0GVPYdRqGtG_TbH3gzfUl192hH1DO2_WrDdrACM,698
|
|
22
23
|
nowfocus/connectors/todo_template.py,sha256=R37fA2LXo8_LpWIgqozytI5RqIUjGggFHup25xTykII,1572
|
|
23
24
|
nowfocus/connectors/todotxt.py,sha256=QCZjbIhY4Lm37YD0GsKJQUqbj7s3eYmZGgRwUCndZ5w,3857
|
|
24
25
|
nowfocus/connectors/trello.py,sha256=VqwnvHGXXcljmdf6kRZcE6sfeBQYhped_KVBEBOzWXM,6072
|
|
25
26
|
nowfocus/connectors/txt.py,sha256=iskJsw3dZnI4bIeEDtZCY-aQfKRKtoGATEJ0k13npxI,8125
|
|
26
|
-
nowfocus/connectors/vikunja.py,sha256=
|
|
27
|
-
nowfocus/desktop-extras/nowfocus.desktop,sha256=
|
|
27
|
+
nowfocus/connectors/vikunja.py,sha256=sutd-loOjYT0njtEIT-E_E_EG9KTdsJfsYd1mHeqNBE,8807
|
|
28
|
+
nowfocus/desktop-extras/nowfocus.desktop,sha256=0kWsx0ZfvPbubGG1uuFSHxxYUw2GV9Ly_rtlboM1mak,294
|
|
28
29
|
nowfocus/desktop-extras/nowfocus.png,sha256=P5rn6-0EAJa2WXf4SJoaNtLRUfiV3LdsOroPKsR6GfA,15148
|
|
29
30
|
nowfocus/desktop-extras/nowfocus.svg,sha256=nps7naZzuhWWuKzQbpvxr9wLyzjmzMPzNHSBQMVetOo,2137
|
|
30
31
|
nowfocus/icon/cancel.png,sha256=Hy9A7KdO13MsXguIgoTI276mECN07rzd6hGbIqxSl7c,506
|
|
@@ -52,9 +53,9 @@ nowfocus/icon/settings.svg,sha256=fgkGJouPPtZLxZn2nr_5pEp9MdhRSRaW9mtdxhJHDuQ,39
|
|
|
52
53
|
nowfocus/sound/bell-xylophone-g.mp3,sha256=1OBcRWvD87AGNcq1uZFR8HqG0nanJykImERfVDVxHD4,53891
|
|
53
54
|
nowfocus/sound/dinner-bell.mp3,sha256=hjjO0xqA4uXpYw9KLwwlBnrVfRhVq1K5OXzwlMXhRn4,113620
|
|
54
55
|
nowfocus/sound/xylophone-chord.mp3,sha256=gwgBSqhMt5PMzT5N03Z6TvDgipQZfnkEz_o81Rq5Z1U,131806
|
|
55
|
-
nowfocus-0.5.
|
|
56
|
-
nowfocus-0.5.
|
|
57
|
-
nowfocus-0.5.
|
|
58
|
-
nowfocus-0.5.
|
|
59
|
-
nowfocus-0.5.
|
|
60
|
-
nowfocus-0.5.
|
|
56
|
+
nowfocus-0.5.9.dist-info/licenses/LICENSE,sha256=fSJzoHs1EOCwEd7FIyokFeGEma7NKmTVEdHkCr5OIV4,35127
|
|
57
|
+
nowfocus-0.5.9.dist-info/METADATA,sha256=TBWJV37J-P1zGbLQlDAMB_G-ejxuSxsdufG7wupsem8,6707
|
|
58
|
+
nowfocus-0.5.9.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
59
|
+
nowfocus-0.5.9.dist-info/entry_points.txt,sha256=RbYY19-irSoNVglNeNnL9D36cHft7aKsaEGEYoSH3pA,51
|
|
60
|
+
nowfocus-0.5.9.dist-info/top_level.txt,sha256=3uLd9BwmfarZwqVUxkSJuVwJ8qHzjThte8rt_UYG7tE,9
|
|
61
|
+
nowfocus-0.5.9.dist-info/RECORD,,
|
nowfocus/version_migrator.py
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
# update time_target format
|
|
3
|
-
for id, tt in user['time_targets']['lists'].items():
|
|
4
|
-
if 'within_value' not in tt:
|
|
5
|
-
print("Updating time target to new format ",tt)
|
|
6
|
-
tt['within_value'] = tt['num_days']
|
|
7
|
-
tt['within_unit'] = 'days'
|
|
8
|
-
print(tt)
|
|
9
|
-
if 'status' not in tt:
|
|
10
|
-
tt['status'] = True
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
for id, tt in user['time_targets']['tasks'].items():
|
|
14
|
-
if 'within_value' not in tt:
|
|
15
|
-
print("Updating time target to new format ",tt)
|
|
16
|
-
tt['within_value'] = tt['num_days']
|
|
17
|
-
tt['within_unit'] = 'days'
|
|
18
|
-
print(tt)
|
|
19
|
-
if 'status' not in tt:
|
|
20
|
-
tt['status'] = True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|