nowfocus 0.4.0__py3-none-any.whl → 0.4.4__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
@@ -29,8 +29,6 @@ except Exception as e:
29
29
  gi.require_version('AppIndicator3', '0.1')
30
30
  from gi.repository import AppIndicator3 as appindicator
31
31
 
32
- # from dbus_idle import IdleMonitor
33
-
34
32
  # Set working dir to file location
35
33
  os.chdir(os.path.dirname(os.path.realpath(__file__)))
36
34
 
@@ -57,85 +55,64 @@ setproctitle.setproctitle(conf.app_name)
57
55
  print(conf.app_name +" running from " + os.path.dirname(os.path.realpath(__file__)))
58
56
 
59
57
  class Application(Gtk.Application):
58
+ icon_tick_number = 0
59
+
60
60
  def __init__(self, *args, **kwargs):
61
61
  super().__init__(*args, application_id="org.nowfocus.nowfocus", **kwargs)
62
62
 
63
- # try:
64
- # # To put everything here...
65
- # # this doesn't work because as soon as an exception occurs ii jumps to the handler and breaks all the following code.
63
+ try:
66
64
 
67
- # except Exception as e:
68
- # 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 ')
69
- # traceback.print_tb(e.__traceback__)
70
- # return None
71
-
72
- self.window = None
65
+
66
+
67
+ self.window = None
73
68
 
74
- self.is_running = False
75
- self.session = default_session()
69
+ self.is_running = False
70
+ self.device_in_use = True
71
+ self.UserIdleTime = UserIdleTime()
72
+ self.last_user_idle_check_time = None
73
+ self.session = default_session()
76
74
 
77
- self.menu_tasks = {}
78
- self.list_menus = {}
75
+ self.menu = Gtk.Menu()
76
+ self.menu_tasks = {}
77
+ self.list_menus = {}
79
78
 
80
- self.indicator = appindicator.Indicator.new(conf.app_name, os.path.abspath('icon/icon-1.svg'), appindicator.IndicatorCategory.APPLICATION_STATUS)
79
+ self.indicator = appindicator.Indicator.new(conf.app_name, os.path.abspath('icon/icon-1.svg'), appindicator.IndicatorCategory.APPLICATION_STATUS)
80
+ self.indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
81
+ self.indicator.set_menu(self.menu)
81
82
 
82
- self.indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
83
+ if conf.is_first_load:
84
+ import install
85
+ install.run_first_load_actions()
83
86
 
84
- self.menu = Gtk.Menu()
85
- # menu.set_reserve_toggle_size(False) # skip menu left padding, doesn't work
87
+ utils.db_schema_update()
86
88
 
87
- utils.db_init()
88
- utils.db_schema_update()
89
+ self.async_refresh()
89
90
 
91
+ # utils.db_cleanup()
90
92
 
91
- # self.update_menu()
92
- self.async_refresh()
93
+ main_tick_timer = GLib.timeout_add_seconds(1, self.tick)
93
94
 
94
- # utils.db_cleanup()
95
+ self.resume_session_from_db()
95
96
 
96
- self.indicator.set_menu(self.menu)
97
+ self.start_pipe()
98
+ self.open_task_window()
97
99
 
98
- main_tick_timer = GLib.timeout_add_seconds(1, self.tick)
100
+ # Testing
101
+ # time.sleep(3)
102
+ # self.open_session_options_dialog('test_param')
103
+ # self.open_settings_window() #for testing
104
+ # self.open_new_task_dialog() #for testing
105
+ # self.print_time_totals()
99
106
 
100
- try:
101
- db_session = db_query("SELECT value FROM system WHERE field = 'session'")
107
+ signal.signal(signal.SIGINT, self.quit)
108
+ signal.signal(signal.SIGUSR1, self.signal_handler)
109
+ signal.signal(signal.SIGUSR2, self.signal_handler)
102
110
 
103
- if db_session:
104
- s = json.loads(db_session[0]['value'])
105
- s['start_time'] = datetime.strptime(s['start_time'],'%Y-%m-%d %H:%M:%S.%f')
106
- self.session = s
107
- self.is_running = True
108
- dbg("resuming session",s['label'],l=2, s='session')
111
+ Gtk.main()
109
112
  except Exception as e:
110
- dbg("Error resuming session",e,l=1)
111
-
112
- self.UserIdleTime = UserIdleTime()
113
-
114
- self.pipethread = threading.Thread(target=self.check_pipe)
115
- self.pipethread.daemon = True
116
- self.pipethread.start()
117
-
118
- # Testing
119
- # time.sleep(3)
120
- # self.open_session_options_dialog('test_param')
121
-
122
- # self.open_settings_window() #for testing
123
- # self.open_task_window() #for testing
124
-
125
- # time.sleep(2)
126
- # self.open_new_task_dialog() #for testing
127
-
128
- # time.sleep(2)
129
- # self.print_time_totals()
130
-
131
- # signal.signal(signal.SIGINT, signal.SIG_DFL)
132
- signal.signal(signal.SIGINT, self.quit)
133
- signal.signal(signal.SIGUSR1, self.signal_handler)
134
- signal.signal(signal.SIGUSR2, self.signal_handler)
135
-
136
- Gtk.main()
137
-
138
-
113
+ 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 ')
114
+ traceback.print_tb(e.__traceback__)
115
+ self.quit()
139
116
 
140
117
 
141
118
  def print_time_totals(self = None, widget = None):
@@ -176,25 +153,13 @@ class Application(Gtk.Application):
176
153
  exit()
177
154
 
178
155
 
179
- def seconds_since_user_active(self):
180
- # returns seconds of inactivity
181
- # See https://stackoverflow.com/questions/67083083/how-to-get-idle-time-in-linux or
182
-
183
- # Works on x11 but not wayland
184
- # Requires xprintidle (sudo apt install xprintidle)
185
- # idle_time = int(int(subprocess.getoutput('xprintidle')) / 1000)
186
-
187
- # Version that works, using: https://github.com/bkbilly/dbus_idle
188
- # but has many deps
189
- # Requires:
190
- # sudo apt install meson libdbus-glib-1-dev patchelf
191
- # pip install dbus-idle
156
+ def get_seconds_since_user_active(self):
157
+
158
+ if self.last_user_idle_check_time != now().replace(microsecond=0):
159
+ self.last_user_idle_check_time = now().replace(microsecond=0)
160
+ self.seconds_since_user_active = self.UserIdleTime.get()
192
161
 
193
- # idle_time = int(int(IdleMonitor().get_dbus_idle()) / 1000)
194
- # return idle_time
195
-
196
- return self.UserIdleTime.get()
197
-
162
+ return self.seconds_since_user_active
198
163
 
199
164
 
200
165
  def toggle_do_not_disturb(self, widget):
@@ -212,84 +177,106 @@ class Application(Gtk.Application):
212
177
 
213
178
  def tock(self):
214
179
 
215
- if 'do-not-disturb' in self.session:
216
- return None
217
-
218
- afk_time = self.seconds_since_user_active()
219
- # print("Idle time: "+str(afk_time))
180
+ user_inactive_time = self.get_seconds_since_user_active()
181
+ # print("user_inactive_time: "+str(user_inactive_time))
220
182
 
221
183
  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 )
222
184
 
223
- if (int(time_difference(conf.todo_sync_time)) / 60) > conf.user['todolist_refresh_interval'] * 60 :
185
+ if (int(time_difference(conf.todo_sync_time)) / 60) > conf.user['todolist_refresh_interval'] * 60:
186
+ # TODO: use individual todo_refresh_times
224
187
  self.async_refresh()
225
188
 
226
- # TODO: use individual todo_refresh_times
227
-
228
189
  minutes = (int(self.session['duration']) / 60)
229
190
 
230
- if(self.is_running == False):
191
+ if self.check_device_became_inactive():
192
+ self.handle_device_became_inactive()
193
+
194
+ elif self.device_in_use == False or 'do-not-disturb' in self.session:
195
+ # Do nothing
196
+ dbg("Do not disturb is active")
197
+
198
+ elif self.is_running:
199
+
200
+ if self.session['label'] in conf.user['custom_pomodoro_intervals']:
201
+ check = conf.user['custom_pomodoro_intervals'][self.session['label']]
202
+ else:
203
+ check = conf.user['pomodoro_interval']
204
+
205
+ if float(minutes / check ).is_integer():
206
+ notify.Notification.new("Time for a Break?","You've been working on "+self.session['label']+" for "+str(minutes)+" minutes. ", None).show()
207
+
208
+ playsound('sound/bell-xylophone-g.mp3',False)
209
+
231
210
 
232
- if num_is_multiple_of(minutes,conf.user['randomness_interrupt_interval']):
233
- if afk_time < 30:
211
+ if 'target' in self.session:
212
+ t = self.session['target']
213
+
214
+ t['percent'] = round(( (t['starting_value'] + minutes) / t['value'] ) * 100,1)
215
+ print("At", t['percent'], "% of ", t['scope'], " target")
216
+
217
+ if t['type'] == 'max':
218
+ if t['percent'] >= 100:
219
+
220
+ notify.Notification.new("Time is up for this "+t['scope'],"You'r at "+str(round(t['percent']))+"% of your "+str(t['value'])+" minutes in the last "+str(t['within_value'])+" "+ t['within_unit'], None).show()
221
+
222
+ playsound('sound/dinner-bell.mp3',False)
223
+
224
+ elif t['type'] == 'min' and round(t['starting_value'] + minutes) == t['value']:
225
+ 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()
234
226
 
235
- notify.Notification.new("What Am I doing?","Your randomness timer is at "+str(minutes)+" minutes. ", None).show()
227
+ playsound('sound/xylophone-chord.mp3',False)
236
228
 
237
- self.open_task_window()
238
-
239
- playsound('sound/dinner-bell.mp3',False)
229
+ elif num_is_multiple_of(minutes,conf.user['randomness_interrupt_interval']):
230
+
231
+ notify.Notification.new("What Am I doing?","Your randomness timer is at "+str(minutes)+" minutes. ", None).show()
232
+
233
+ self.open_task_window()
234
+
235
+ playsound('sound/dinner-bell.mp3',False)
240
236
 
241
- elif afk_time > 120:
242
- self.session['duration'] = 0
243
- self.session['start_time'] = now()
244
- print("Idle time reset. afk:", afk_time, self.session)
245
237
 
238
+ def check_device_became_inactive(self):
239
+ if self.get_seconds_since_user_active() > (conf.user['device_not_in_use_threshold'] * 60):
240
+ if self.device_in_use == True:
241
+ self.device_in_use = False
242
+ return True
246
243
  else:
247
- if afk_time > 120:
248
- # only show this once
249
- if afk_time < 181:
250
- self.open_task_window(None,{'afk_time':afk_time})
251
- else:
252
- if self.session['label'] in conf.user['custom_pomodoro_intervals']:
253
- check = conf.user['custom_pomodoro_intervals'][self.session['label']]
254
- else:
255
- check = conf.user['pomodoro_interval']
256
-
257
- if float(minutes / check ).is_integer():
258
- notify.Notification.new("Time for a Break?","You've been working on "+self.session['label']+" for "+str(minutes)+" minutes. ", None).show()
244
+ self.device_in_use = True
245
+ return False
259
246
 
260
- playsound('sound/bell-xylophone-g.mp3',False)
261
247
 
248
+ def handle_device_became_inactive(self):
249
+ self.user_last_inactive = now()
262
250
 
263
- if 'target' in self.session:
264
- t = self.session['target']
251
+ user_inactive_time = self.get_seconds_since_user_active()
252
+ dbg('device_became_inactive ',l=-1)
265
253
 
266
- t['percent'] = round(( (t['starting_value'] + minutes) / t['value'] ) * 100,1)
267
- print("At", t['percent'], "% of ", t['scope'], " target")
254
+ if self.is_running and 'do-not-disturb' not in self.session:
268
255
 
269
- if t['type'] == 'max':
270
- if t['percent'] >= 100:
256
+ self.open_task_window(None,{'user_inactive_time':user_inactive_time})
271
257
 
272
- notify.Notification.new("Time is up for this "+t['scope'],"You'r at "+str(round(t['percent']))+"% of your "+str(t['value'])+" minutes in the last "+str(t['within_value'])+" "+ t['within_unit'], None).show()
258
+ else:
259
+ self.session['duration'] = self.session['duration'] - user_inactive_time
260
+ if self.session['duration'] > 60:
261
+ utils.db_save_session(self.session)
273
262
 
274
- playsound('sound/dinner-bell.mp3',False)
263
+ self.session['duration'] = 0
264
+ self.session['start_time'] = now()
265
+ dbg("Recording:", user_inactive_time, self.session)
275
266
 
276
- elif t['type'] == 'min' and round(t['starting_value'] + minutes) == t['value']:
277
- 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()
278
-
279
- playsound('sound/xylophone-chord.mp3',False)
267
+ if 'do-not-disturb' not in self.session and conf.user['randomness_interrupt_interval'] > 0:
268
+ self.open_task_window(None)
280
269
 
281
-
282
270
 
283
- icon_tick_number = 0
284
-
285
271
  def tick(self):
286
272
 
287
273
  # check for suspend indicated by gap in tick intervals
288
274
  time_since_last_tick = round(time_difference(self.session['start_time']) - self.session['duration'])
289
275
  if time_since_last_tick > 10:
276
+
290
277
  dbg(time_since_last_tick, " seconds since last tick. Probably just woke from suspend. ")
291
278
  if self.is_running:
292
- self.open_task_window(None,{'afk_time':time_since_last_tick})
279
+ self.open_task_window(None,{'user_inactive_time':time_since_last_tick})
293
280
  else:
294
281
  self.session['start_time'] = now()
295
282
 
@@ -306,25 +293,44 @@ class Application(Gtk.Application):
306
293
 
307
294
  label = self.session['label'] + ": " + sec_to_time(duration)
308
295
 
309
- self.indicator.set_icon_full(os.path.abspath('icon/icon-'+str(self.icon_tick_number)+'.svg'),label)
310
-
296
+ icon = 'icon-'+str(self.icon_tick_number)+'.svg'
297
+
311
298
  else:
312
299
 
313
- label = conf.user['default_text']
314
- if duration > 60 and duration % 2:
315
- self.indicator.set_icon_full(os.path.abspath('icon/icon-red.svg'),label)
300
+ label = conf.user['default_text'] +" "+ sec_to_time(duration)
301
+
302
+ if duration > 60 and num_is_multiple_of(duration, 2):
303
+ icon = 'icon-red.svg'
316
304
  else:
317
- self.indicator.set_icon_full(os.path.abspath('icon/icon-1.svg'),label)
305
+ icon = 'icon-1.svg'
318
306
 
319
307
  # https://lazka.github.io/pgi-docs/#AyatanaAppIndicator3-0.1/classes/Indicator.html#AyatanaAppIndicator3.Indicator.set_label
308
+
309
+ self.indicator.set_icon_full(os.path.abspath('icon/'+icon),label)
320
310
  self.indicator.set_label(label,label)
321
311
 
322
- if num_is_multiple_of(self.icon_tick_number,3):
323
- self.refresh_all_changed_todo_files()
324
-
312
+ if num_is_multiple_of(duration,5): # check every 5 seconds
313
+ if self.device_in_use:
314
+ self.refresh_all_changed_todo_files()
315
+ elif self.get_seconds_since_user_active() < 60:
316
+ self.device_in_use = True
317
+ self.handle_device_became_active()
318
+ else:
319
+ # TODO: incriment a user away timer
320
+ dbg("User is still away")
321
+
325
322
  return True
326
323
 
327
324
 
325
+ def handle_device_became_active(self):
326
+ dbg('device_became_active! ',l=-1)
327
+ self.user_last_active = now()
328
+
329
+ if self.is_running == False:
330
+ self.session['start_time'] = now()
331
+ self.session['duration'] = 0
332
+
333
+
328
334
  def refresh_all_changed_todo_files(self):
329
335
  for id, todo_config in conf.user['todolists'].items():
330
336
  if todo_config['status'] and 'watch_file' in todo_config:
@@ -349,6 +355,20 @@ class Application(Gtk.Application):
349
355
  handle_todo_read_error(todo_config,e)
350
356
 
351
357
 
358
+ def resume_session_from_db(self):
359
+ try:
360
+ db_session = db_query("SELECT value FROM system WHERE field = 'session'")
361
+
362
+ if db_session:
363
+ s = json.loads(db_session[0]['value'])
364
+ s['start_time'] = datetime.strptime(s['start_time'],'%Y-%m-%d %H:%M:%S.%f')
365
+ self.session = s
366
+ self.is_running = True
367
+ dbg("resuming session",s['label'],l=2, s='session')
368
+ except Exception as e:
369
+ dbg("Error resuming session",e,l=1)
370
+
371
+
352
372
  def start_task(self, w = None, task_data_or_id = None, transfer_current_session_time = False):
353
373
 
354
374
  if isinstance(task_data_or_id, dict):
@@ -428,7 +448,7 @@ class Application(Gtk.Application):
428
448
 
429
449
 
430
450
  def run_task_command(self,command):
431
- print("running task command:", command)
451
+ dbg("running task command:", command,l=-1)
432
452
 
433
453
  self.running_command_task_label = copy.copy(self.session['label'])
434
454
 
@@ -580,7 +600,7 @@ class Application(Gtk.Application):
580
600
 
581
601
  def async_refresh(self, w=None, single_todo = None):
582
602
 
583
- self.indicator.set_label("Refreshing Todolists", "Wide")
603
+ self.indicator.set_label("Refreshing Todolists", "Refreshing Todolists")
584
604
  menu_item = Gtk.MenuItem.new_with_label("Refreshing Todolists")
585
605
  self.menu.append(menu_item)
586
606
  self.menu.show_all()
@@ -733,24 +753,20 @@ class Application(Gtk.Application):
733
753
  dbg('Signal received',sig,s='signals')
734
754
 
735
755
  if sig == signal.SIGUSR1:
736
- # try:
737
- # print('TaskWindow._instance',TaskWindow._instance)
738
- # if TaskWindow._instance:
739
- # self.taskwindow.destroy()
740
- # else:
741
- # self.open_task_window()
742
-
743
- # except AttributeError:
744
756
  self.open_task_window()
745
-
746
757
  elif sig == signal.SIGUSR2:
747
758
  self.open_session_options_dialog()
748
-
749
759
  else:
750
760
  dbg("no handler for received signal",s='signals',l=3)
751
761
 
762
+
763
+ def start_pipe(self):
764
+ self.pipethread = threading.Thread(target=self.check_pipe)
765
+ self.pipethread.daemon = True
766
+ self.pipethread.start()
767
+
768
+
752
769
  def check_pipe(self):
753
- # print("Listening to pipe at ",conf.pipe)
754
770
 
755
771
  try:
756
772
  with open(conf.pipe, "r") as pipe:
@@ -820,7 +836,6 @@ def startup():
820
836
  except Exception as e:
821
837
  print(e)
822
838
 
823
-
824
839
  try:
825
840
  os.mkfifo(conf.pipe)
826
841
  dbg("Named pipe created successfully!", s="cli")
@@ -836,7 +851,7 @@ def startup():
836
851
 
837
852
 
838
853
  except FileExistsError:
839
- dbg("Named pipe exists, application must be running (or improperly shut down.) ",s="cli")
854
+ print("Named pipe exists, application must be running (or improperly shut down.) ")
840
855
 
841
856
  # if args: pass to pipe and exit
842
857
  if args.task:
nowfocus/conf.py CHANGED
@@ -18,11 +18,14 @@ user_data_dir = GLib.get_user_data_dir()+"/"+app_id
18
18
  Path(user_data_dir).mkdir(parents=True, exist_ok=True)
19
19
 
20
20
  user_settings_dir = GLib.get_user_config_dir()+"/"+app_id
21
- Path(user_settings_dir).mkdir(parents=True, exist_ok=True)
21
+ ''' Depreciated. use user_data_dir instead '''
22
22
 
23
+ db_file = user_data_dir+"/data.db"
24
+ settings_file = user_data_dir+"/nowfocus-settings.json"
23
25
  debug_level = 1 # dev value
24
26
  debug_systems = []
25
- pipe = "/tmp/"+app_id+"-pipe" # Will that work?
27
+ pipe = "/tmp/"+app_id+"-pipe"
28
+ is_first_load = False
26
29
 
27
30
  # key and type must be the same, (Seems redundant but it's is quite helpful)
28
31
  connectors = {
@@ -59,9 +62,10 @@ prototype_settings = {
59
62
  "pomodoro_interval": 40,
60
63
  "open_task_window_fullscreen": True,
61
64
  "show_task_window_sidebars": False,
62
- "randomness_interrupt_interval":5,
65
+ "randomness_interrupt_interval":7, #minutes
66
+ "device_not_in_use_threshold":3.5, #minutes
63
67
  "default_text": "What am I doing?",
64
- "todolist_refresh_interval":1,
68
+ "todolist_refresh_interval":1, #hours
65
69
  "version":0.4,
66
70
  "display_todolist_as_top_level_list":'auto',
67
71
  'max_top_level_menu_items':10,
@@ -69,7 +73,7 @@ prototype_settings = {
69
73
  'invoice_hourly_rate':0,
70
74
 
71
75
  "custom_pomodoro_intervals": {
72
- "email":7
76
+ "email":7 #minutes
73
77
  },
74
78
 
75
79
  'prompts':'What am I doing?\nWhy am I here?\nWhat could I do?\nWhat do I wish to accomplish?\nWhat is my aim?\nWhat\'s next',
@@ -84,11 +88,11 @@ prototype_settings = {
84
88
  },
85
89
 
86
90
  "todolists": {
87
- "Example Todo":{
88
- "id":"Example Todo",
91
+ "Nowfocus Todo":{
92
+ "id":"Nowfocus Todo",
89
93
  "type": "txt",
90
- "label": "Example Todo",
91
- "file": "example-todo.txt",
94
+ "label": "Nowfocus Todo",
95
+ "file": user_data_dir+'/nowfocus-todo.txt',
92
96
  "timetracker":"Example CSV",
93
97
  "status":True
94
98
  }
@@ -98,36 +102,43 @@ prototype_settings = {
98
102
  "id": "Example CSV",
99
103
  "label": "Example CSV",
100
104
  "type":"csv",
101
- "file":"sessions.csv",
105
+ "file":user_data_dir+'/nowfocus-timetracking-spreadsheet.csv',
102
106
  "status":True
103
107
  }
104
108
  }
105
109
  }
106
110
 
107
- if os.path.isfile(user_settings_dir+"/user_settings.json"):
111
+ if os.path.isfile(settings_file):
112
+ with open(settings_file, "r") as file:
113
+ settings = json.load(file)
114
+
115
+ # Backward compatibility, check in old settings dir
116
+ elif os.path.isfile(user_settings_dir+"/user_settings.json"):
108
117
  with open(user_settings_dir+"/user_settings.json", "r") as file:
109
- settings_file = json.load(file)
118
+ settings = json.load(file)
110
119
  else:
120
+
111
121
  print("Setting up initial settings file")
112
- settings_file = {}
122
+ is_first_load = True
123
+ settings = {}
113
124
 
114
125
 
115
126
  user = {}
116
127
 
117
- # Merge user_settings.json with prototype settings
128
+ # Merge settings with prototype settings
118
129
  for key, val in prototype_settings.items():
119
130
 
120
- if settings_file and key in connectors:
131
+ if settings and key in connectors:
121
132
  user[key] = {}
122
133
 
123
134
  # merge and validate todolist and timetracker settings against connector prototypes
124
- for c_key, c_val in settings_file[key].items():
135
+ for c_key, c_val in settings[key].items():
125
136
 
126
137
  if c_val['type'] in connectors[key]:
127
138
  proto = copy.copy(connectors[key][c_val['type']])
128
139
  user[key][c_key] = proto
129
140
  else:
130
- print('ERROR: no connector for type '+c_val['type']+' in user_settings.json','skipping that connector',c_val)
141
+ print('ERROR: no connector for type '+c_val['type']+' in settings_file','skipping that connector',c_val)
131
142
  continue
132
143
 
133
144
  # print('validate user_settings connector against prototype.','user',c_val,'proto',proto)
@@ -142,46 +153,28 @@ for key, val in prototype_settings.items():
142
153
  else:
143
154
  print("Adding missing: connection field "+p_field+")")
144
155
 
145
- elif key in settings_file and type(settings_file[key]) == type(val):
146
- user[key] = settings_file[key]
156
+ elif key in settings and type(settings[key]) == type(val):
157
+ user[key] = settings[key]
147
158
  else:
148
159
  user[key] = val
149
160
 
150
161
  # print(json.dumps(user, indent=4))
151
162
  # print(json.dumps(connectors['todolists'], indent=4))
152
163
 
153
- # update time_target format
154
- for id, tt in user['time_targets']['lists'].items():
155
- if 'within_value' not in tt:
156
- print("Updating time target to new format ",tt)
157
- tt['within_value'] = tt['num_days']
158
- tt['within_unit'] = 'days'
159
- print(tt)
160
- if 'status' not in tt:
161
- tt['status'] = True
162
164
 
163
-
164
- for id, tt in user['time_targets']['tasks'].items():
165
- tt
166
- if 'within_value' not in tt:
167
- print("Updating time target to new format ",tt)
168
- tt['within_value'] = tt['num_days']
169
- tt['within_unit'] = 'days'
170
- print(tt)
171
- if 'status' not in tt:
172
- tt['status'] = True
173
-
174
-
175
- with open(user_settings_dir+"/user_settings.json","w") as settings_file:
165
+ with open(settings_file,"w") as settings_file:
176
166
  json.dump(user, settings_file)
177
167
 
178
-
179
168
  todo_connectors = {}
180
169
  timetracker_connectors = {}
181
170
 
182
- # Load used connector modules
183
- for id, todolist in user['todolists'].items():
184
- todo_connectors[todolist['type']] = importlib.import_module('connectors.'+todolist['type'])
185
-
186
- for id, timetracker in user['timetrackers'].items():
187
- timetracker_connectors[timetracker['type']] = importlib.import_module('connectors.'+timetracker['type'])
171
+ try:
172
+
173
+ for id, todolist in user['todolists'].items():
174
+ todo_connectors[todolist['type']] = importlib.import_module('connectors.'+todolist['type'])
175
+
176
+ for id, timetracker in user['timetrackers'].items():
177
+ timetracker_connectors[timetracker['type']] = importlib.import_module('connectors.'+timetracker['type'])
178
+ except Exception as e:
179
+ print("error loading connector")
180
+ print(e)