nowfocus 0.2.13__py3-none-any.whl → 0.4.2__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 CHANGED
@@ -13,6 +13,7 @@ from playsound3 import playsound
13
13
  import setproctitle
14
14
  import psutil
15
15
  import argparse
16
+ import traceback
16
17
 
17
18
  import gi
18
19
  gi.require_version('Gtk', '3.0')
@@ -28,7 +29,7 @@ except Exception as e:
28
29
  gi.require_version('AppIndicator3', '0.1')
29
30
  from gi.repository import AppIndicator3 as appindicator
30
31
 
31
- from dbus_idle import IdleMonitor
32
+ # from dbus_idle import IdleMonitor
32
33
 
33
34
  # Set working dir to file location
34
35
  os.chdir(os.path.dirname(os.path.realpath(__file__)))
@@ -39,6 +40,8 @@ sys.path.append(os.path.dirname(__file__))
39
40
  # from . import conf # this works in module context but not running as pile-of-files
40
41
  import conf # this works running as pile-of-files but not in module context without sys.path.append
41
42
 
43
+ from user_idle_time import UserIdleTime
44
+
42
45
  import utils
43
46
  from utils import *
44
47
 
@@ -54,20 +57,24 @@ setproctitle.setproctitle(conf.app_name)
54
57
  print(conf.app_name +" running from " + os.path.dirname(os.path.realpath(__file__)))
55
58
 
56
59
  class Application(Gtk.Application):
60
+ icon_tick_number = 0
61
+
57
62
  def __init__(self, *args, **kwargs):
58
- super().__init__(*args, application_id="org.example.myapp", **kwargs)
63
+ super().__init__(*args, application_id="org.nowfocus.nowfocus", **kwargs)
64
+
65
+ # try:
66
+ # # To put everything here...
67
+ # # this doesn't work because as soon as an exception occurs ii jumps to the handler and breaks all the following code.
59
68
 
69
+ # except Exception as e:
70
+ # print(conf.app_name +' had a pretty bad error. Please submit the following trace as an issue on the git repo or email it to the developers ')
71
+ # traceback.print_tb(e.__traceback__)
72
+ # return None
73
+
60
74
  self.window = None
61
75
 
62
76
  self.is_running = False
63
- self.session = {
64
- "label":"Randomness",
65
- "extended_label": 'Randomness',
66
- "start_time":datetime.now(),
67
- "duration":0,
68
- 'task':{},
69
- 'notes':'',
70
- }
77
+ self.session = default_session()
71
78
 
72
79
  self.menu_tasks = {}
73
80
  self.list_menus = {}
@@ -80,7 +87,7 @@ class Application(Gtk.Application):
80
87
  # menu.set_reserve_toggle_size(False) # skip menu left padding, doesn't work
81
88
 
82
89
  utils.db_init()
83
- utils.db_update()
90
+ utils.db_schema_update()
84
91
 
85
92
 
86
93
  # self.update_menu()
@@ -90,7 +97,6 @@ class Application(Gtk.Application):
90
97
 
91
98
  self.indicator.set_menu(self.menu)
92
99
 
93
- # main_tick_timer = GLib.timeout_add_seconds(conf.user['tick_interval'], self.tick)
94
100
  main_tick_timer = GLib.timeout_add_seconds(1, self.tick)
95
101
 
96
102
  try:
@@ -105,7 +111,7 @@ class Application(Gtk.Application):
105
111
  except Exception as e:
106
112
  dbg("Error resuming session",e,l=1)
107
113
 
108
- utils.start_todo_file_watchers()
114
+ self.UserIdleTime = UserIdleTime()
109
115
 
110
116
  self.pipethread = threading.Thread(target=self.check_pipe)
111
117
  self.pipethread.daemon = True
@@ -133,7 +139,6 @@ class Application(Gtk.Application):
133
139
 
134
140
 
135
141
 
136
-
137
142
  def print_time_totals(self = None, widget = None):
138
143
 
139
144
  # SELECT extended_label, (SUM(duration) / 60 ) FROM sessions GROUP BY extended_label
@@ -157,39 +162,40 @@ class Application(Gtk.Application):
157
162
 
158
163
  def quit(self, widget_or_signal_source=None, condition=None):
159
164
  print("Adios ", conf.app_name)
160
- # print("widget_or_signal_source ", widget_or_signal_source)
161
- # print("condition ", condition)
162
165
 
163
166
  if self.is_running:
164
- print('Caching active session', self.session['label'])
167
+ dbg('Caching active session', self.session['label'])
165
168
  db_set_session_cache(self.session)
169
+
166
170
  try:
167
- # print("before os.remove(conf.pipe)")
168
171
  os.remove(conf.pipe)
169
- print("Pipe removed")
170
172
  except Exception as e:
171
- print("Error removing conf.pipe in quit",e)
173
+ dbd("Error removing conf.pipe in quit",e)
172
174
 
173
175
  notify.uninit()
174
176
  Gtk.main_quit()
175
177
  exit()
176
178
 
177
179
 
178
- def check_afk_time(self):
180
+ def seconds_since_user_active(self):
179
181
  # returns seconds of inactivity
180
- # See https://stackoverflow.com/questions/67083083/how-to-get-idle-time-in-linux or
182
+ # See https://stackoverflow.com/questions/67083083/how-to-get-idle-time-in-linux or
181
183
 
182
184
  # Works on x11 but not wayland
183
185
  # Requires xprintidle (sudo apt install xprintidle)
184
186
  # idle_time = int(int(subprocess.getoutput('xprintidle')) / 1000)
185
187
 
186
- # Currently using: https://github.com/bkbilly/dbus_idle
188
+ # Version that works, using: https://github.com/bkbilly/dbus_idle
189
+ # but has many deps
187
190
  # Requires:
188
191
  # sudo apt install meson libdbus-glib-1-dev patchelf
189
192
  # pip install dbus-idle
190
193
 
191
- idle_time = int(int(IdleMonitor().get_dbus_idle()) / 1000)
192
- return idle_time
194
+ # idle_time = int(int(IdleMonitor().get_dbus_idle()) / 1000)
195
+ # return idle_time
196
+
197
+ return self.UserIdleTime.get()
198
+
193
199
 
194
200
 
195
201
  def toggle_do_not_disturb(self, widget):
@@ -210,7 +216,7 @@ class Application(Gtk.Application):
210
216
  if 'do-not-disturb' in self.session:
211
217
  return None
212
218
 
213
- afk_time = self.check_afk_time()
219
+ afk_time = self.seconds_since_user_active()
214
220
  # print("Idle time: "+str(afk_time))
215
221
 
216
222
  dbg('Last todo todo_sync_time', conf.todo_sync_time, 'Time diff',int(time_difference(conf.todo_sync_time)),'Auto refresh interval * 60', (conf.user['todolist_refresh_interval'] * 60), s="todoloading", l=3 )
@@ -224,7 +230,7 @@ class Application(Gtk.Application):
224
230
 
225
231
  if(self.is_running == False):
226
232
 
227
- if float(minutes / conf.user['randomness_interrupt_interval']).is_integer():
233
+ if num_is_multiple_of(minutes,conf.user['randomness_interrupt_interval']):
228
234
  if afk_time < 30:
229
235
 
230
236
  notify.Notification.new("What Am I doing?","Your randomness timer is at "+str(minutes)+" minutes. ", None).show()
@@ -243,7 +249,6 @@ class Application(Gtk.Application):
243
249
  # only show this once
244
250
  if afk_time < 181:
245
251
  self.open_task_window(None,{'afk_time':afk_time})
246
- # session_options_dialog(None, 'test input_data')
247
252
  else:
248
253
  if self.session['label'] in conf.user['custom_pomodoro_intervals']:
249
254
  check = conf.user['custom_pomodoro_intervals'][self.session['label']]
@@ -260,7 +265,7 @@ class Application(Gtk.Application):
260
265
  t = self.session['target']
261
266
 
262
267
  t['percent'] = round(( (t['starting_value'] + minutes) / t['value'] ) * 100,1)
263
- print("At ", t['percent'], "% of ", t['scope'], " target")
268
+ print("At", t['percent'], "% of ", t['scope'], " target")
264
269
 
265
270
  if t['type'] == 'max':
266
271
  if t['percent'] >= 100:
@@ -273,66 +278,80 @@ class Application(Gtk.Application):
273
278
  notify.Notification.new("Good job on doing "+self.session['label'],"You've reached your target of "+str(t['value'])+" minutes "+str(t['within_value'])+" "+ t['within_unit'], None).show()
274
279
 
275
280
  playsound('sound/xylophone-chord.mp3',False)
276
-
277
281
 
278
- # maybe add a target % to the session and show with tick
279
-
280
- icon_tick_number = 0
281
-
282
+
282
283
  def tick(self):
283
- menu = self.menu
284
- indicator = self.indicator
285
284
 
286
285
  # check for suspend indicated by gap in tick intervals
287
- time_since_last_tick = round(time_difference(self.session['start_time']) - self.session['duration'])
286
+ time_since_last_tick = round(time_difference(self.session['start_time']) - self.session['duration'])
288
287
  if time_since_last_tick > 10:
289
- print(time_since_last_tick, " seconds since last tick. Probably just woke from suspend. ")
290
-
288
+ dbg(time_since_last_tick, " seconds since last tick. Probably just woke from suspend. ")
291
289
  if self.is_running:
292
290
  self.open_task_window(None,{'afk_time':time_since_last_tick})
293
291
  else:
294
- print("resetting randomness timer")
295
- self.session['duration'] = 0
296
292
  self.session['start_time'] = now()
297
293
 
298
- # print("tick!")
299
- self.session['duration'] = int(time_difference(self.session['start_time']))
294
+ duration = self.session['duration'] = int(time_difference(self.session['start_time']))
300
295
 
301
- if(self.session['duration'] > 2 and (int(self.session['duration']) / 60).is_integer()):
296
+ if num_is_multiple_of(duration,60):
302
297
  self.tock()
303
298
 
304
- if(self.is_running == True):
305
- self.icon_tick_number = self.icon_tick_number + 1
299
+ if self.is_running == True:
300
+ self.icon_tick_number += 1
306
301
 
307
302
  if self.icon_tick_number > 8:
308
303
  self.icon_tick_number = 1
309
304
 
310
- label = self.session['label'] + ": " + sec_to_time(self.session['duration'])
305
+ label = self.session['label'] + ": " + sec_to_time(duration)
306
+
307
+ icon = 'icon-'+str(self.icon_tick_number)+'.svg'
311
308
 
312
- indicator.set_icon_full(os.path.abspath('icon/icon-'+str(self.icon_tick_number)+'.svg'),label)
313
-
314
309
  else:
315
310
 
316
- # label = random.choice(conf.idle_messages) # Cool but makes menu bounce around #Could be paused when the menu opens
317
- label = conf.user['default_text']
318
- if self.session['duration'] > 60 and self.session['duration'] % 2:
319
- indicator.set_icon_full(os.path.abspath('icon/icon-red.svg'),label)
311
+ label = conf.user['default_text'] +" "+ sec_to_time(duration)
312
+
313
+ if duration > 60 and num_is_multiple_of(duration, 2):
314
+ icon = 'icon-red.svg'
315
+
320
316
  else:
321
- indicator.set_icon_full(os.path.abspath('icon/icon-1.svg'),label)
317
+ icon = 'icon-1.svg'
322
318
 
323
319
  # https://lazka.github.io/pgi-docs/#AyatanaAppIndicator3-0.1/classes/Indicator.html#AyatanaAppIndicator3.Indicator.set_label
324
- indicator.set_label(label, "Wide")
325
320
 
326
- for todo in conf.todo_sync_required:
327
- # print('tick noticed a todo needing refreshment, time since refresh: ',time_difference(conf.todo_sync_times[todo]))
321
+ self.indicator.set_icon_full(os.path.abspath('icon/'+icon),label)
322
+ self.indicator.set_label(label,label)
328
323
 
329
- if time_difference(conf.todo_sync_times[todo]) > 4:
330
- # print('tick noticed a todo needing refreshment')
331
- self.async_refresh(None,conf.user['todolists'][todo])
332
- conf.todo_sync_required = {}
324
+
325
+ if num_is_multiple_of(self.icon_tick_number,3):
326
+ self.refresh_all_changed_todo_files()
327
+
333
328
  return True
334
329
 
335
330
 
331
+ def refresh_all_changed_todo_files(self):
332
+ for id, todo_config in conf.user['todolists'].items():
333
+ if todo_config['status'] and 'watch_file' in todo_config:
334
+ self.refresh_todo_if_file_changed(todo_config)
335
+
336
+
337
+ def refresh_todo_if_file_changed(self, todo_config):
338
+
339
+ try:
340
+ todo_m_time = round(os.stat(todo_config['file']).st_mtime)
341
+
342
+ if todo_config['id'] not in conf.todo_file_change_times:
343
+ conf.todo_file_change_times[todo_config['id']] = todo_m_time
344
+
345
+ elif todo_m_time != conf.todo_file_change_times[todo_config['id']]:
346
+ dbg(todo_config['id']+" file was changed!",s='todoloading')
347
+ self.async_refresh(None,todo_config)
348
+ conf.todo_file_change_times[todo_config['id']] = todo_m_time
349
+
350
+ except Exception as e:
351
+ # TODO: consider how to quietly handle errors when refresh is not prompted by the user and temporarily disabling
352
+ handle_todo_read_error(todo_config,e)
353
+
354
+
336
355
  def start_task(self, w = None, task_data_or_id = None, transfer_current_session_time = False):
337
356
 
338
357
  if isinstance(task_data_or_id, dict):
@@ -356,7 +375,10 @@ class Application(Gtk.Application):
356
375
 
357
376
  if(self.is_running == True):
358
377
  self.stop_task()
359
-
378
+ elif(self.session['duration'] > 60):
379
+ # Log randomness session (to internal db only) if longer than one minute
380
+ utils.db_save_session(self.session)
381
+
360
382
 
361
383
  self.is_running = True
362
384
 
@@ -450,26 +472,20 @@ class Application(Gtk.Application):
450
472
  try:
451
473
 
452
474
  done_thread = threading.Thread(target=conf.todo_connectors[todolist_conf['type']].mark_task_done, args=(task,) )
475
+
453
476
  conf.todo_sync_times[todolist_conf['id']] = now() # this is to avoid causing a refresh, perhaps not the best though
454
477
 
455
- # Other Options:
456
- # make a custom class extending Thread with callback method that runs del conf.file_watch_ignores[todolist_conf['id']]
457
- # Complicated
458
- # deal with file_watch_ignores in the connector
459
- # poor seperation
460
- #
461
478
  done_thread.start()
462
479
 
463
480
  db_query("UPDATE tasks set status = '0' WHERE id = ? ",(task['id'],) )
464
481
  utils.reindex_one(task)
465
482
 
466
- # print('remove menu item')
467
483
  self.menu_tasks[task['id']].destroy()
468
-
484
+
469
485
  playsound('sound/xylophone-chord.mp3',False)
470
486
 
471
487
  except Exception as e:
472
- error_notice('Error Marking Task Done'," Marking "+ task['label']+" as done in "+todolist_conf['label']+" had a serious failure",e )
488
+ error_notice('Error Marking Task Done'," Marking "+ task['label']+" as done in "+todolist_conf['label']+" had a serious failure", e=e )
473
489
 
474
490
 
475
491
 
@@ -533,19 +549,12 @@ class Application(Gtk.Application):
533
549
  self.menu.show_all()
534
550
 
535
551
  self.is_running = False
536
- # print(utils.get_times(task))
537
552
  if action != 'cancel':
538
553
  notify.Notification.new("Focused on "+session['label']+" for "+sec_to_time(session['duration']),utils.pretty_dict(utils.get_times(task)), None).show()
539
554
  # notify.Notification.new(action.capitalize()+" "+session['label']+" "+sec_to_time(session['duration']),utils.pretty_dict(utils.get_times(task)), None).show()
540
555
 
541
556
  # Start randomness timer
542
- self.session = {
543
- "label": 'Randomness',
544
- "extended_label": 'Randomness',
545
- "start_time": now(),
546
- "duration":0,
547
- "task":{}
548
- }
557
+ self.session = default_session()
549
558
 
550
559
  self.tick()
551
560
 
@@ -554,9 +563,6 @@ class Application(Gtk.Application):
554
563
  self.menu.get_children()[0].destroy()
555
564
  self.do_not_disturb_menu_item.set_label("Do Not Disturb")
556
565
 
557
- else:
558
- print('no task running!')
559
-
560
566
 
561
567
  def task_running_menu_additions(self):
562
568
 
@@ -577,7 +583,7 @@ class Application(Gtk.Application):
577
583
 
578
584
  def async_refresh(self, w=None, single_todo = None):
579
585
 
580
- self.indicator.set_label("Refreshing Todolists", "Wide")
586
+ self.indicator.set_label("Refreshing Todolists", "Refreshing Todolists")
581
587
  menu_item = Gtk.MenuItem.new_with_label("Refreshing Todolists")
582
588
  self.menu.append(menu_item)
583
589
  self.menu.show_all()
nowfocus/conf.py CHANGED
@@ -52,20 +52,19 @@ connectors = {
52
52
  todo_sync_time = datetime.now()
53
53
  todo_sync_times = {}
54
54
 
55
- todo_sync_required = {}
56
- file_watchers = {}
57
- file_watch_ignores = {}
55
+ todo_file_change_times = {}
56
+ timers = {}
58
57
 
59
58
  prototype_settings = {
60
59
  "pomodoro_interval": 40,
61
60
  "open_task_window_fullscreen": True,
61
+ "show_task_window_sidebars": False,
62
62
  "randomness_interrupt_interval":5,
63
63
  "default_text": "What am I doing?",
64
64
  "todolist_refresh_interval":1,
65
- "version":0.2,
65
+ "version":0.4,
66
66
  "display_todolist_as_top_level_list":'auto',
67
67
  'max_top_level_menu_items':10,
68
- # 'tick_interval':1,
69
68
  'hours_search_timeframe':'this year',
70
69
  'invoice_hourly_rate':0,
71
70
 
@@ -39,7 +39,6 @@ def add_new_task(user_conf,list,task_label):
39
39
 
40
40
  todotxt.add(task)
41
41
  todotxt.save()
42
- # task.add_project
43
42
 
44
43
  t = {
45
44
  'id':task_label,
@@ -87,6 +86,7 @@ def get_todos(user_conf):
87
86
  }
88
87
  }
89
88
 
89
+ priority_letter_to_number_map = {'A':1,'B':2,'C':3,'D':4}
90
90
 
91
91
  todotxt = pytodotxt.TodoTxt(user_conf['file'])
92
92
  for t in todotxt.parse():
@@ -99,7 +99,6 @@ def get_todos(user_conf):
99
99
  'parent_id':user_conf['id'],
100
100
  'parent_label':user_conf['label'],
101
101
  'status':1,
102
- # 'priority':1 max, 5 min, 0 none,
103
102
  'todolist':user_conf['id'],
104
103
  'data':t.attributes #TODO: add other things like date etc
105
104
  }
@@ -107,6 +106,12 @@ def get_todos(user_conf):
107
106
  if t.is_completed:
108
107
  tasks[id]['status'] = 0
109
108
 
109
+ if t.priority:
110
+ try:
111
+ tasks[id]['priority'] = priority_letter_to_number_map[t.priority]
112
+ except:
113
+ tasks[id]['priority'] = 5
114
+
110
115
 
111
116
  if t.projects:
112
117
  l = t.projects[0]
@@ -137,5 +142,5 @@ def get_todos(user_conf):
137
142
  def launch(user_conf, item = None, category = None):
138
143
  ''' Open todolist '''
139
144
 
140
- # It would b very nice to open a the right line number but xdg-open doesn't support that...
145
+ # It would b very nice to open the right line number but xdg-open doesn't support that...
141
146
  utils.open_external(user_conf['file'])
@@ -108,7 +108,7 @@ def mark_task_done(task):
108
108
  if data[line_no].strip().startswith('[ ]'):
109
109
  data[line_no] = data[line_no].replace('[ ]', '[x]')
110
110
  else:
111
- data[line_no] = data[line_no].replace(data[line_no].lstrip(), '[x] '+ data[line_no].lstrip() )
111
+ data[line_no] = data[line_no].replace(data[line_no].lstrip(), '[x]'+ data[line_no].lstrip() )
112
112
 
113
113
  # write everything back
114
114
  with open(file_uri, 'w') as file:
@@ -176,7 +176,18 @@ def get_todos(user_conf):
176
176
  status = 0
177
177
 
178
178
  label = label.removeprefix('[ ]').removeprefix('[]').strip()
179
- #TODO: use markdown title syntax as list name in addition to indentation
179
+ #TODO: use markdown title syntax as list name in addition to indentation?
180
+
181
+ # tags = ''
182
+ # # hashtag tagging
183
+ # if label.split("#").len() > 1:
184
+ # parts = label.split("#")
185
+ # print("label has hashtag",parts)
186
+
187
+ # label = parts[0].strip()
188
+ # del parts[0]
189
+ # tags = ",".join(parts)
190
+
180
191
 
181
192
  indent = len(line) - len(line.lstrip())
182
193
  indent_str = line[0:indent]
@@ -229,6 +240,7 @@ def get_todos(user_conf):
229
240
  'todolist':user_conf['id'],
230
241
  'status': status,
231
242
  'priority': priority,
243
+ # 'tags':tags,
232
244
  'data':{
233
245
  'line_no':line_no,
234
246
  'original_line':line,
@@ -9,8 +9,6 @@ import requests
9
9
  import conf
10
10
  import utils
11
11
 
12
- # UPDATE sessions SET task_id = "Vikunja_t" || task_id WHERE todolist = 'Vikunja';
13
- # UPDATE sessions SET parent_id = "Vikunja_l" || parent_id WHERE todolist = 'Vikunja';
14
12
 
15
13
  def vikunja_item_id(id, item_type, user_conf):
16
14
  return user_conf['id'] +'_'+ item_type[0] + str(id)
@@ -20,7 +18,7 @@ def add_new_task(user_conf,parent_list,task_label):
20
18
  headers = {'content-type': 'application/json'}
21
19
  data = {'title': task_label}
22
20
 
23
- utils.dbg('add_new_task() parent_list',parent_list, l=0)
21
+ utils.dbg('add_new_task() parent_list',parent_list, l=-1)
24
22
 
25
23
  response = requests.put(user_conf['url']+"api/v1/projects/"+str(parent_list['data']['id'])+"/tasks",json=data, headers=head)
26
24
 
@@ -104,7 +102,6 @@ def get_todos(user_conf):
104
102
  }
105
103
 
106
104
 
107
- priorities = {'DO NOW':1,'Urgent':2,'high':3}
108
105
  headers = {"Authorization": "Bearer "+user_conf['token']}
109
106
  projects_lists = requests.get(user_conf['url']+"api/v1/projects", headers=headers).json()
110
107
 
@@ -139,6 +136,9 @@ def get_todos(user_conf):
139
136
 
140
137
  lists[id]['data']['accepts_tasks'] = True
141
138
 
139
+ # print(p['title']+' is_archived:',p['is_archived'])
140
+ # BUG: archived list aren't provided (But used to be ?) so sublists end up orphaned and dangerous...
141
+
142
142
  if p['is_archived']:
143
143
  lists[id]['status'] = -1
144
144
  else:
@@ -152,6 +152,10 @@ def get_todos(user_conf):
152
152
  if parent_id in lists:
153
153
  lists[id]['parent_label'] = lists[parent_id]['label']
154
154
 
155
+ if lists[parent_id]['status'] == -1:
156
+ lists[id]['status'] = -1
157
+
158
+
155
159
 
156
160
  # NOTE: Originally tasks where queried per list, however this no longer works well because it requires a 'view' id, which comes wih various un-predictable baked-in filters (like done=true). Using the tasks/all api endpoint avoids this but quickly hits the default maxitemsperpage limit (which could, less obviously, show up in the per list method).
157
161
 
@@ -204,7 +208,6 @@ def get_todos(user_conf):
204
208
  # ?per_page=10000
205
209
 
206
210
 
207
-
208
211
  response = requests.get(user_conf['url']+"api/v1/tasks/all", headers=headers)
209
212
  all_tasks = response.json()
210
213
 
@@ -218,8 +221,6 @@ def get_todos(user_conf):
218
221
  # print(json.dumps(all_tasks, indent=4))
219
222
  utils.dbg("Got ",len(all_tasks),"Vikunja tasks", s='vikunja', l=2 )
220
223
 
221
- utils.dbg("Got ",len(all_tasks),"Vikunja tasks", s='vikunja', l=2 )
222
-
223
224
  for i, itemIter in enumerate(all_tasks):
224
225
 
225
226
  t = all_tasks[i]
@@ -228,7 +229,7 @@ def get_todos(user_conf):
228
229
 
229
230
  # utils.dbg(t, s='vikunja', l=3)
230
231
 
231
- # Limit to asks assigned, created by, or favorated by user
232
+ # Limit to tasks assigned, created by, or favorated by user
232
233
  if user_conf["username"]:
233
234
  if t['is_favorite'] != True:
234
235
 
@@ -264,13 +265,12 @@ def get_todos(user_conf):
264
265
  tasks[id]['status'] = -1
265
266
 
266
267
  except Exception as e:
267
- print("No list found for", t['title']," list_id",list_id)
268
+ utils.dbg("No list found for", t['title']," list_id",list_id, s='vikunja')
268
269
  # raise e
269
270
 
270
271
  if t['done'] == True:
271
272
  tasks[id]['status'] = 0
272
273
 
273
- # Prioritize if "due_date" is soon or passed (and not: "0001-01-01T00:00:00Z")
274
274
  if 'due_date' in t and t['due_date'] != "0001-01-01T00:00:00Z":
275
275
 
276
276
  due_date = datetime.strptime(t['due_date'],'%Y-%m-%dT%H:%M:%SZ')
@@ -282,14 +282,13 @@ def get_todos(user_conf):
282
282
  if due_seconds > -86400:
283
283
  tasks[id]['priority'] = 2
284
284
 
285
- # prioritize favorites
286
- if t['is_favorite'] == True:
285
+ if t['priority'] and t['priority'] > 1:
286
+ # Vikunja priority is 1 = lowest, 5 = highest
287
+ #
288
+ tasks[id]['priority'] = utils.invert_number_scale(utils.clamp(utils.force_number(t['priority']),0,5))
289
+ elif t['is_favorite'] == True:
287
290
  tasks[id]['priority'] = 2
288
- elif t['priority'] in priorities:
289
- print("Priority task", t['title'])
290
- tasks[id]['priority'] = priorities[t['priority']]
291
- # print(tasks[id])
292
-
291
+
293
292
  todos = {'lists':lists,'tasks':tasks}
294
293
  return todos
295
294
 
@@ -87,9 +87,9 @@ class NewTaskWDialog(Gtk.Dialog):
87
87
  todolist_conf = conf.user['todolists'][parent_list['todolist']]
88
88
  try:
89
89
 
90
- conf.file_watch_ignores[todolist_conf['id']] = True
91
90
  task = conf.todo_connectors[todolist_conf['type']].add_new_task(todolist_conf,parent_list,task_label)
92
- del conf.file_watch_ignores[todolist_conf['id']]
91
+
92
+ clear_todo_file_change_time(todolist_conf)
93
93
 
94
94
  dbg('connector add task response',task)
95
95
 
@@ -121,9 +121,8 @@ class NewTaskWDialog(Gtk.Dialog):
121
121
  if conf.debug_level > 1:
122
122
  raise e
123
123
 
124
- error_notice('Error adding tasks',"Adding "+ task_label+" to "+todolist_conf['label']+" had a serious failure",e )
124
+ error_notice('Error adding tasks',"Adding "+ task_label+" to "+todolist_conf['label']+" had a serious failure",e) # NOTE: e, in the case of a key error, only prints the bad key, not the error type
125
125
 
126
-
127
126
 
128
127
  elif response == Gtk.ResponseType.CANCEL:
129
128
  print("Cancel button clicked")