nowfocus 0.2.12__py3-none-any.whl → 0.4.0__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/settings.py CHANGED
@@ -64,60 +64,19 @@ def after_todo_settings_change(app, todo = None):
64
64
  if todo:
65
65
  todo = utils.get_todo_by_id(todo)
66
66
  if todo['status']:
67
-
68
67
  app.async_refresh(todo)
69
- utils.stop_todo_file_watchers(todo)
70
- utils.start_todo_file_watchers(todo)
71
-
72
68
  else:
73
69
  utils.db_deactivate_todo(todo['id'])
74
70
  utils.reindex()
75
- utils.stop_todo_file_watchers(todo)
76
71
  app.update_menu()
77
72
 
78
73
  else:
79
74
  app.async_refresh()
80
- utils.stop_todo_file_watchers()
81
- utils.start_todo_file_watchers()
82
75
 
83
76
 
84
77
  class SettingsWindow(Gtk.Window):
85
78
 
86
79
 
87
- def show_sessions(self, widget = None, label_text = "Most Recent Sessions", order_by = 'start_time', limit = 35, passed_sessions = None):
88
-
89
- self.sessions_box.foreach(lambda child: child.destroy())
90
-
91
- if passed_sessions:
92
- dbg("using Passed_sessions",passed_sessions,s='settings')
93
- sessions = passed_sessions
94
- else:
95
- dbg("show_sessions: order_by:",order_by, 'limit',limit, s='settings')
96
- sessions = db_query(" SELECT * FROM sessions WHERE "+sessions_timeframe_sql()+" ORDER BY "+order_by+" DESC LIMIT ? ",(limit,))
97
-
98
- # print('sessions')
99
- # print(sessions)
100
-
101
- label = Gtk.Label()
102
- if passed_sessions:
103
- label.set_markup('<b>'+label_text+'</b>')
104
- else:
105
- label.set_markup('<b>'+str(limit)+' '+label_text+' of '+conf.user['hours_search_timeframe']+'</b>')
106
- self.sessions_box.add(label)
107
-
108
- for ls in sessions:
109
- dbg('Add session to session_box',ls['extended_label'],s='settings')
110
- btn = Gtk.Button(label=ls['extended_label']+' '+str(ls['duration'] / 60 / 60)[:4]+' hr on '+ls['start_time'][:10])
111
-
112
- btn.set_halign(Gtk.Align.START)
113
- btn.set_relief(Gtk.ReliefStyle.NONE)
114
-
115
- btn.connect('clicked', lambda button_widget, ls: SessionEditDialog(None, self, ls),ls )
116
-
117
- self.sessions_box.add(btn)
118
-
119
- self.sessions_box.show_all()
120
-
121
80
  def scroll_box(self, parent_widget = None, height = 300):
122
81
 
123
82
  # print('parent_widget')
@@ -136,7 +95,7 @@ class SettingsWindow(Gtk.Window):
136
95
 
137
96
 
138
97
  def __init__(self, parent=None, **kwargs):
139
- self.app = parent #NOTE: This doens't look like it will work when called from task_window...
98
+ self.app = parent #NOTE: This doesn't look like it will work when called from task_window...
140
99
  Gtk.Window.__init__(self, title="Settings")
141
100
  self.set_border_width(15)
142
101
  self.set_position(position=1)
@@ -241,6 +200,7 @@ class SettingsWindow(Gtk.Window):
241
200
  grid.attach(self.settings_updater('default_text','What am I Doing?','Entry'),0,(row:=row+1),5,1)
242
201
 
243
202
  grid.attach(self.settings_updater('open_task_window_fullscreen',True,'Switch'),0,(row:=row+1),5,1)
203
+ grid.attach(self.settings_updater('show_task_window_sidebars',True,'Switch'),0,(row:=row+1),5,1)
244
204
 
245
205
  grid.attach(self.settings_updater('pomodoro_interval',25,'SpinButton',"(minutes)"),0,(row:=row+1),5,1)
246
206
 
@@ -248,8 +208,7 @@ class SettingsWindow(Gtk.Window):
248
208
 
249
209
  grid.attach(self.settings_updater('todolist_refresh_interval', 3, 'SpinButton',"(hours)"),0,(row:=row+1),5,1)
250
210
 
251
- # grid.attach(self.settings_updater('tick_interval', 18, 'SpinButton',"\nMust be an even number fraction of 60. (requires restart)"),0,(row:=row+1),5,1)
252
-
211
+
253
212
  # grid.attach(self.settings_updater('invoice_hourly_rate', 33, 'SpinButton',""),0,(row:=row+1),5,1)
254
213
 
255
214
  grid.attach(self.settings_updater('hours_search_timeframe', 'auto', 'ComboBoxText',"\nDefault timetracking range for hours shown in main window and invoicing", options = list(hours_search_timeframes().keys())),0,(row:=row+1),5,1)
@@ -360,11 +319,9 @@ class SettingsWindow(Gtk.Window):
360
319
  self.sessions_page.add(print_time_totals_button)
361
320
 
362
321
  show_recent_sessions_button = Gtk.Button(label="Show recent sessions")
363
- show_recent_sessions_button.connect("clicked", self.show_sessions, 'Recent Sessions', 'start_time')
364
322
  self.sessions_page.add(show_recent_sessions_button)
365
323
 
366
324
  show_long_sessions_button = Gtk.Button(label="Show long sessions")
367
- show_long_sessions_button.connect("clicked", self.show_sessions, 'Longest Sessions', 'duration')
368
325
  self.sessions_page.add(show_long_sessions_button)
369
326
 
370
327
  self.sessions_scroller = self.scroll_box(self.sessions_page)
@@ -372,7 +329,12 @@ class SettingsWindow(Gtk.Window):
372
329
  self.sessions_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5)
373
330
  self.sessions_scroller.add(self.sessions_box)
374
331
 
375
- self.show_sessions()
332
+ show_sessions(None, self, self.sessions_box)
333
+ show_recent_sessions_button.connect("clicked", show_sessions, self, self.sessions_box, 'Recent Sessions', 'start_time')
334
+ show_long_sessions_button.connect("clicked", show_sessions, self, self.sessions_box, 'Longest Sessions', 'duration')
335
+
336
+ self.SessionEditDialog = SessionEditDialog # passed to show_sessions
337
+
376
338
 
377
339
  self.show_all()
378
340
 
@@ -585,7 +547,6 @@ class SettingsWindow(Gtk.Window):
585
547
  db_query("DELETE FROM tasks WHERE todolist = ? AND id NOT IN (SELECT task_id FROM sessions)",(id,))
586
548
  db_query("DELETE FROM lists WHERE todolist = ?",(id,))
587
549
  utils.reindex()
588
- utils.stop_todo_file_watchers(connector)
589
550
  self.app.update_menu()
590
551
 
591
552
  del conf.user[connector_category][id]
@@ -1040,9 +1001,7 @@ class EditAddConnectorDialog(Gtk.Dialog):
1040
1001
  if connector_category == 'todolists':
1041
1002
 
1042
1003
  conf.todo_connectors[new['type']] = importlib.import_module('connectors.'+new['type'])
1043
-
1044
- utils.stop_todo_file_watchers(new)
1045
- utils.start_todo_file_watchers(new)
1004
+
1046
1005
  self.app.async_refresh(new)
1047
1006
 
1048
1007
 
nowfocus/styles.css CHANGED
@@ -1,9 +1,3 @@
1
- /* *{
2
- font-size:18px;
3
- } */
4
-
5
-
6
- /* #TaskWindow{ */
7
1
  .large{
8
2
  font-size:25px;
9
3
  }
@@ -11,23 +5,25 @@
11
5
  #FuzzyTask{
12
6
  font-size:30px;
13
7
  padding:12px;
14
-
15
8
  }
16
9
 
17
10
  #RelevantQuestion{
18
11
  font-weight: 100;
19
- font-size:35px;
12
+ font-size: 35px;
20
13
  opacity: .3;
21
14
  }
22
15
 
23
- #Footer{
16
+ .subtle{
24
17
  font-weight: 100;
25
18
  font-size:16px;
26
- opacity: .5;
19
+ opacity: .4;
27
20
  }
28
21
 
29
- #priorityTask{
22
+ .subtle:hover{
23
+ opacity: .7;
24
+ }
30
25
 
26
+ #priorityTask{
31
27
  font-weight: bold;
32
28
  }
33
29
 
@@ -38,6 +34,8 @@
38
34
  .done{
39
35
  text-decoration-line: line-through;
40
36
  text-decoration:line-through;
37
+ opacity: .5;
38
+ font-weight: 100;
41
39
  }
42
40
 
43
41
  #task_rclick_menu{
nowfocus/task_window.py CHANGED
@@ -6,6 +6,7 @@ import utils
6
6
  from utils import *
7
7
 
8
8
  from settings import EditAddTargetDialog, EditTaskCommandDialog
9
+ from session_edit_dialog import SessionEditDialog
9
10
 
10
11
  class TaskWindow(Gtk.Window):
11
12
  css_provider = Gtk.CssProvider()
@@ -18,6 +19,8 @@ class TaskWindow(Gtk.Window):
18
19
 
19
20
  def __init__(self,app,passed_data=None):
20
21
 
22
+ timeit()
23
+
21
24
  if TaskWindow._instance:
22
25
  try:
23
26
  if TaskWindow._instance.taskEntry.get_text():
@@ -67,41 +70,56 @@ class TaskWindow(Gtk.Window):
67
70
  self.shown_tasks = {}
68
71
 
69
72
  self.set_border_width(20)
70
- self.set_position(position=1) # Works on x11 but not wayland (ubuntu 22.04)
73
+ self.set_position(position=1)
71
74
 
72
75
  self.accel_group = Gtk.AccelGroup()
73
76
  self.add_accel_group(self.accel_group)
74
77
 
75
- box = Gtk.VBox(spacing=10)
76
- box.set_halign(Gtk.Align.CENTER)
77
- # box.set_valign(Gtk.Align.CENTER)
78
-
79
- self.add(box)
78
+ self.outer_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0, border_width=0)
79
+ self.add(self.outer_box)
80
80
 
81
- self.header = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=15, border_width=10)
81
+ self.l_sidebar = Gtk.VBox(spacing=5)
82
+ self.l_sidebar.get_style_context().add_class("subtle")
83
+
84
+ self.outer_box.add(self.l_sidebar)
85
+
86
+ self.center_box = Gtk.VBox(spacing=10)
87
+ self.center_box.set_halign(Gtk.Align.CENTER)
82
88
 
83
- # self.header.set_halign(Gtk.Align.CENTER)
89
+ self.outer_box.add(self.center_box)
84
90
 
85
- box.pack_start(self.header,False, False, 0)
91
+ self.header = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=15, border_width=10)
86
92
 
93
+ self.center_box.pack_start(self.header,False, False, 0)
94
+
87
95
  self.recreate_header()
88
96
 
97
+ self.r_sidebar_outer = Gtk.ScrolledWindow()
98
+ self.r_sidebar_outer.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
99
+ self.outer_box.add(self.r_sidebar_outer)
100
+
101
+ self.r_sidebar = Gtk.VBox(spacing=5)
102
+ self.r_sidebar.get_style_context().add_class("subtle")
103
+
104
+ self.r_sidebar.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK)
105
+ self.r_sidebar.add_events(Gdk.EventMask.LEAVE_NOTIFY_MASK)
106
+ self.r_sidebar.connect("enter-notify-event",self.test)
107
+
108
+ self.r_sidebar_outer.add(self.r_sidebar)
109
+
89
110
  self.tick_timer = GLib.timeout_add_seconds(1, self.tick)
90
111
 
91
112
  self.task_entry_overlay = Gtk.Overlay()
92
113
 
93
- # Large fuzzy task input
94
114
  self.taskEntry = Gtk.Entry()
95
- self.taskEntry.set_name("FuzzyTask") # set css id
96
- # self.taskEntry.set_width_chars(59)
115
+ self.taskEntry.set_name("FuzzyTask")
97
116
  self.taskEntry.set_max_width_chars(79)
98
-
99
117
  self.taskEntry.set_placeholder_text("Find Task [Ctrl+F]")
100
118
  self.taskEntry.set_property("tooltip-text", "Find Task [Ctrl+F], press Enter to start work on the first task in the list")
101
119
 
102
120
  self.task_entry_overlay.add(self.taskEntry)
103
121
 
104
- box.pack_start(self.task_entry_overlay,False, False, 0)
122
+ self.center_box.pack_start(self.task_entry_overlay,False, False, 0)
105
123
 
106
124
  self.taskEntry.grab_focus()
107
125
 
@@ -126,10 +144,9 @@ class TaskWindow(Gtk.Window):
126
144
  self.taskEntry.set_text(passed_data['task']['label'])
127
145
 
128
146
 
129
-
130
147
  self.scrolled_window = Gtk.ScrolledWindow()
131
148
  self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
132
- box.pack_start(self.scrolled_window, True, True, 0)
149
+ self.center_box.pack_start(self.scrolled_window, True, True, 0)
133
150
  self.scrolled_window.set_size_request(-1, 350)
134
151
 
135
152
  self.scrolled_window.connect('scroll-event', self.on_scroll) # This doesn't catch scrollbar moves
@@ -142,6 +159,7 @@ class TaskWindow(Gtk.Window):
142
159
 
143
160
  self.total_duration_label = Gtk.Label()
144
161
  self.total_duration_label.set_margin_end(12)
162
+ self.total_duration_label.get_style_context().add_class('subtle')
145
163
  self.total_duration_label.set_halign(Gtk.Align.END)
146
164
  self.task_entry_overlay.add_overlay(self.total_duration_label)
147
165
 
@@ -156,14 +174,14 @@ class TaskWindow(Gtk.Window):
156
174
  # self.timesheet_to_button.connect("clicked",self.timesheet_to_clipboard)
157
175
  # self.timesheet_to_button.set_name("Footer")
158
176
  # self.timesheet_to_button.set_property("tooltip-text","Click to copy CSV timesheet to clipboard")
159
- # box.pack_start(self.timesheet_to_button,False, False, 0)
177
+ # self.center_box.pack_start(self.timesheet_to_button,False, False, 0)
160
178
 
161
179
 
162
180
  self.buttons_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20)
163
181
  self.buttons_box.set_halign(Gtk.Align.CENTER)
164
- self.buttons_box.set_name("Footer")
182
+ self.buttons_box.get_style_context().add_class("subtle")
165
183
 
166
- box.pack_start(self.buttons_box,False, False, 0)
184
+ self.center_box.pack_start(self.buttons_box,False, False, 0)
167
185
 
168
186
  self.settings_button = Gtk.Button(label="Settings")
169
187
  self.settings_button.connect("clicked",self.app.open_settings_window)
@@ -181,7 +199,8 @@ class TaskWindow(Gtk.Window):
181
199
  openable = conf.todo_connectors[todo['type']].launch
182
200
  openable_button = Gtk.Button(label=GLib.markup_escape_text(todo['label']))
183
201
  openable_button.connect("clicked", lambda button_widget,todo=todo, openable=openable: openable(todo))
184
- openable_button.set_property("tooltip-text","Open (new) "+GLib.markup_escape_text(todo['label']))
202
+ openable_button.set_property("tooltip-text","Open "+GLib.markup_escape_text(todo['label']))
203
+
185
204
  self.buttons_box.add(openable_button)
186
205
 
187
206
  except Exception as e:
@@ -193,6 +212,8 @@ class TaskWindow(Gtk.Window):
193
212
  self.buttons_box.add(self.new_task_button)
194
213
 
195
214
  self.show_all()
215
+ timeit()
216
+
196
217
 
197
218
  key, mod = Gtk.accelerator_parse('<Control>n')
198
219
  self.new_task_button.add_accelerator("clicked", self.accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
@@ -205,11 +226,17 @@ class TaskWindow(Gtk.Window):
205
226
  self.connect("window-state-event", self.on_window_state_event)
206
227
 
207
228
  self.taskEntry.connect("changed",self.task_search)
229
+ GLib.idle_add(self.refresh_search_cache)
208
230
 
209
- self.refresh_search_cache()
210
231
  self.connect("destroy", self.on_destroy)
211
232
 
212
-
233
+ def test(self=None, one=None, two=None, **kwargs):
234
+ print('task_window test')
235
+ print(one)
236
+ print(two)
237
+ print(kwargs)
238
+
239
+
213
240
  def on_destroy(self, widget= None):
214
241
  TaskWindow._instance = None
215
242
  print("¡Adios Task Window!")
@@ -221,11 +248,15 @@ class TaskWindow(Gtk.Window):
221
248
  if self.lazy_loadable_tasks:
222
249
  print('Tasks to lazy load ', len(self.lazy_loadable_tasks))
223
250
  for id, t in self.lazy_loadable_tasks.items():
224
- self.add_task_to_list(t)
251
+ self.add_task_to_window(t)
225
252
  self.tasks_box.show_all()
226
253
 
227
254
  self.lazy_loadable_tasks = {}
228
255
 
256
+ def select_list_callback(self, widget, l):
257
+ print('widget',widget,'list',l)
258
+ self.taskEntry.set_text(l['extended_label']+" > ")
259
+ self.taskEntry.grab_focus()
229
260
 
230
261
  def refresh_search_cache(self,w = None):
231
262
  self.search_cache = {}
@@ -242,13 +273,11 @@ class TaskWindow(Gtk.Window):
242
273
 
243
274
  self.session_time.set_label(sec_to_time(self.app.session['duration']))
244
275
  if self.app.session['label'] != self.header_task:
245
- self.recreate_header()
276
+ self.recreate_header()
246
277
 
247
278
  if utils.taskindex_updated_time() > self.search_cache_refresh_time:
248
279
  # print("taskindex was updated, utils.taskindex_updated_time()", utils.taskindex_updated_time(), 'self.search_cache_refresh_time',self.search_cache_refresh_time)
249
280
  self.refresh_search_cache()
250
- # else:
251
- # print("taskindex was not updated",current_data_version)
252
281
 
253
282
  return True # This continues the timer
254
283
 
@@ -292,13 +321,13 @@ class TaskWindow(Gtk.Window):
292
321
  pause_button.connect("clicked", self.recreate_header)
293
322
 
294
323
  pause_button.connect("clicked", self.refresh_search_cache)
295
- pause_button.set_property("tooltip-text", "Pause Task (Ctrl + P)")
324
+ pause_button.set_property("tooltip-text", "Pause Task (Control S)")
296
325
  pause_button.set_relief(Gtk.ReliefStyle.NONE)
297
326
  self.header.add(pause_button)
298
327
 
299
328
  done_button = Gtk.Button()
300
329
  done_button.set_image(Gtk.Image.new_from_file(os.path.abspath('icon/mark-done.png')))
301
- done_button.set_property("tooltip-text", "Mark Task Done (Ctrl + D)")
330
+ done_button.set_property("tooltip-text", "Mark Task Done (Control D)")
302
331
  done_button.connect("clicked", self.app.stop_task,'mark_done')
303
332
  done_button.connect("clicked", self.recreate_header)
304
333
  done_button.connect("clicked", self.refresh_search_cache) # doesn't work, probably because it happens before stop_task
@@ -310,14 +339,17 @@ class TaskWindow(Gtk.Window):
310
339
  cancel_button.set_image(Gtk.Image.new_from_file(os.path.abspath('icon/cancel.png')))
311
340
  cancel_button.connect("clicked", self.app.stop_task,"cancel")
312
341
  cancel_button.connect("clicked", self.recreate_header)
313
- cancel_button.set_property("tooltip-text", "Discard timer (Ctrl + X)")
342
+ cancel_button.set_property("tooltip-text", "Discard timer (Control Q)")
314
343
  cancel_button.set_relief(Gtk.ReliefStyle.NONE)
315
344
  self.header.add(cancel_button)
316
345
 
317
- key, mod = Gtk.accelerator_parse('<Control>p')
346
+ key, mod = Gtk.accelerator_parse('<Control>p') # for backward compatibility
347
+ pause_button.add_accelerator("clicked", self.accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
348
+
349
+ key, mod = Gtk.accelerator_parse('<Control>S')
318
350
  pause_button.add_accelerator("clicked", self.accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
319
351
 
320
- key, mod = Gtk.accelerator_parse('<Control>x')
352
+ key, mod = Gtk.accelerator_parse('<Control>q')
321
353
  cancel_button.add_accelerator("clicked", self.accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
322
354
 
323
355
  key, mod = Gtk.accelerator_parse('<Control>d')
@@ -346,12 +378,33 @@ class TaskWindow(Gtk.Window):
346
378
 
347
379
 
348
380
  self.header.show_all()
381
+ GLib.idle_add(self.create_sidebars)
349
382
 
350
383
  try:
351
384
  self.taskEntry.grab_focus()
352
385
  except Exception:
353
386
  pass
354
-
387
+
388
+ def create_sidebars(self):
389
+ timeit()
390
+ if conf.user['open_task_window_fullscreen'] and conf.user['show_task_window_sidebars']:
391
+ self.r_sidebar_outer.set_size_request(350, -1)
392
+ self.l_sidebar.set_size_request(350, -1)
393
+
394
+ self.SessionEditDialog = SessionEditDialog # passed to show_sessions
395
+
396
+ #show lists on left
397
+ self.l_sidebar.foreach(lambda child: child.destroy())
398
+
399
+ self.l_sidebar.add(choose_from_lists(self.select_list_callback, 'None', None, False))
400
+
401
+ #show sessions on right
402
+ show_sessions(None, self, self.r_sidebar, None, 'start_time', '30',None, 30)
403
+ self.l_sidebar.show_all()
404
+ self.r_sidebar.show_all()
405
+ timeit()
406
+
407
+
355
408
  def on_notes_changed(self,buffer):
356
409
  notes = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False)
357
410
  self.app.session['notes'] = notes
@@ -364,20 +417,18 @@ class TaskWindow(Gtk.Window):
364
417
  self.refresh_search_cache()
365
418
 
366
419
 
367
- def task_search(self,widget):
420
+ def task_search(self,widget = None):
368
421
 
369
422
  self.tasks_box.foreach(lambda child: child.destroy())
370
- self.tasks_box.show_all()
371
423
  self.shown_tasks.clear()
372
424
 
373
- self.search_term = i = widget.get_text()
425
+ self.search_term = self.taskEntry.get_text()
374
426
 
375
- # utils.dbg({"task search":i},s='taskwindow')
376
- if i in self.search_cache:
377
- tasks = self.search_cache[i]
427
+ if self.search_term in self.search_cache:
428
+ tasks = self.search_cache[self.search_term]
378
429
  else:
379
- tasks = utils.taskindex_search(i)
380
- self.search_cache[i] = tasks
430
+ tasks = utils.taskindex_search(self.search_term)
431
+ self.search_cache[self.search_term] = tasks
381
432
 
382
433
  total_duration = 0
383
434
  self.lazy_loadable_tasks = {}
@@ -385,12 +436,12 @@ class TaskWindow(Gtk.Window):
385
436
  if tasks:
386
437
  count = 0
387
438
  for id, t in tasks.items():
388
- count = count + 1
439
+ count += 1
389
440
  if 'duration' in t and t['duration']:
390
441
  total_duration += int(t['duration'])
391
442
 
392
443
  if count < self.num_initial_tasks:
393
- self.add_task_to_list(t)
444
+ self.add_task_to_window(t)
394
445
  else:
395
446
  self.lazy_loadable_tasks[id] = t
396
447
 
@@ -399,30 +450,27 @@ class TaskWindow(Gtk.Window):
399
450
  self.total_duration_label.set_markup('<b>'+str(round(total_duration / 60 / 60,1))+'</b> hrs\n'+conf.user['hours_search_timeframe'] )
400
451
 
401
452
 
402
-
403
- def add_task_to_list(self,t):
453
+ def add_task_to_window(self,t):
404
454
 
405
455
  try:
406
- search_str = self.search_term
407
456
  utils.dbg("add_task_to_list "+ str(t['extended_label']), "status",t['status'], s='taskwindow',l=3)
408
457
 
409
- # self.shown_tasks[t['id']] = Gtk.Button() # Works but does not accept popovers
410
458
  self.shown_tasks[t['id']] = Gtk.MenuButton(popover=self.task_rclick_menu)
411
- self.shown_tasks[t['id']].set_halign(Gtk.Align.START)
412
- self.shown_tasks[t['id']].set_hexpand(True)
459
+ button = self.shown_tasks[t['id']]
460
+ button.set_halign(Gtk.Align.START)
461
+ button.set_hexpand(True)
413
462
 
414
463
  label = Gtk.Label()
415
464
 
416
- # button_context = self.shown_tasks[t['id']].get_style_context().add_class("large")
417
465
  extended_label = GLib.markup_escape_text(t['extended_label'],)
466
+
467
+ if len(extended_label) > 110:
468
+ extended_label = extended_label[:110]+"..."
418
469
 
419
- if len(search_str) > 1:
420
-
421
- # fts5 match highlighting, not that good because it highlights the whole word rather than the matching part...
422
- # extended_label = extended_label.replace('[[',"<b>").replace(']]',"</b>")
470
+ if len(self.search_term) > 1:
423
471
 
424
- extended_label = extended_label.replace(search_str,"<b>"+search_str+"</b>")
425
- extended_label = extended_label.replace(search_str.capitalize(),"<b>"+search_str.capitalize()+"</b>") # Cheesy
472
+ extended_label = extended_label.replace(self.search_term,"<b>"+self.search_term+"</b>")
473
+ extended_label = extended_label.replace(self.search_term.capitalize(),"<b>"+self.search_term.capitalize()+"</b>") # Cheesy but kind of works
426
474
 
427
475
  if "duration" in t and t['duration']:
428
476
  extended_label += " ("+sec_to_time(t['duration'])+")"
@@ -430,28 +478,22 @@ class TaskWindow(Gtk.Window):
430
478
  if t['id'] in conf.user['task_commands'] and conf.user['task_commands'][t['id']]['status']:
431
479
  extended_label += " ["+GLib.markup_escape_text(conf.user['task_commands'][t['id']]['command'])+"]"
432
480
 
433
- if t['priority']:
434
- extended_label = str(t['priority']) +" "+ extended_label
435
481
 
436
482
  if not t['status']:
437
- # utils.dbg("add strikethrough to done task "+t['extended_label'],l=3,s="taskwindow")
438
- # button_context.add_class("done")
439
- label.set_markup('<s>'+extended_label+'</s>')
483
+ button.get_style_context().add_class("done")
484
+ extended_label = '<s>'+extended_label+'</s>'
440
485
 
441
486
  elif t['priority'] > 0:
442
- label.set_name('priorityTask')
443
- label.set_markup(extended_label)
444
- else:
445
- label.set_markup(extended_label)
487
+ extended_label = str(t['priority']) +" "+ extended_label
488
+ button.get_style_context().add_class("bold")
446
489
 
447
- self.shown_tasks[t['id']].add(label)
490
+ label.set_markup(extended_label)
491
+ button.add(label)
448
492
 
449
- # self.shown_tasks[t['id']].set_size_request(955, -1)
450
- self.shown_tasks[t['id']].connect("button-release-event", self.select_task, t['id'])
451
- self.shown_tasks[t['id']].connect("activate", self.select_task, None, t['id'])
452
- self.shown_tasks[t['id']].set_relief(Gtk.ReliefStyle.NONE)
453
- self.tasks_box.add(self.shown_tasks[t['id']])
454
- self.tasks_box.show_all()
493
+ button.connect("button-release-event", self.select_task, t['id'])
494
+ button.connect("activate", self.select_task, None, t['id'])
495
+ button.set_relief(Gtk.ReliefStyle.NONE)
496
+ self.tasks_box.add(button)
455
497
 
456
498
 
457
499
  except Exception as e:
@@ -486,8 +528,12 @@ class TaskWindow(Gtk.Window):
486
528
  w.set_halign(Gtk.Align.START)
487
529
  w.set_relief(Gtk.ReliefStyle.NONE)
488
530
  w.connect('clicked',self.app.mark_done,t)
531
+
532
+ w.connect('clicked',lambda button, self: self.task_rclick_menu.hide(),self)
533
+ w.connect('clicked',lambda button, self, t: self.shown_tasks[t['id']].destroy(),self,t)
489
534
  vbox.pack_start(w, True, True, 5)
490
535
 
536
+
491
537
  # Reassign session/randomness to be on this task,
492
538
  w = Gtk.Button(label="Reassign last "+ str(round((self.app.session['duration'] / 60),1))+" minutes to this task" )
493
539
  w.set_halign(Gtk.Align.START)
@@ -612,7 +658,6 @@ class TaskWindow(Gtk.Window):
612
658
  # utils.dbg("key_press",key,s="taskwindow",l=1)
613
659
  # utils.dbg("key_press event.state",event.state,s="taskwindow",l=1)
614
660
  # utils.dbg("key_press_event",event,s="taskwindow",l=1)
615
- # utils.dbg("ModifierType is CONTROL_MASK",Gdk.ModifierType.CONTROL_MASK,s="taskwindow",l=3)
616
661
 
617
662
  if (event.state & Gdk.ModifierType.CONTROL_MASK) or key == 'Control_L':
618
663
  self.modifyer_keys['control'] = True
@@ -0,0 +1,82 @@
1
+ import os
2
+ import platform
3
+ import subprocess
4
+
5
+ class UserIdleTime():
6
+ def __init__(self, platform = None, **kwargs):
7
+
8
+ self.getters = {
9
+ 'linux_wayland': self.get_idle_seconds_linux_wayland,
10
+ 'linux_x': self.get_idle_seconds_linux_x,
11
+ 'mac': self.get_idle_seconds_mac,
12
+ 'windows': self.get_idle_seconds_windows,
13
+ }
14
+
15
+ if platform:
16
+ self.platform = platform
17
+ else:
18
+ self.detect_platform()
19
+
20
+ print('UserIdleTime platform set to',self.platform)
21
+
22
+ def get (self) :
23
+ ''' Returns int of seconds since user was active '''
24
+ try:
25
+ return int(self.getters[self.platform]())
26
+ except Exception as e:
27
+ print(' CheckIdleTime failed')
28
+ print(e)
29
+ return 0
30
+
31
+
32
+
33
+ def detect_platform (self):
34
+
35
+ match (platform.system()):
36
+ case ('Linux'):
37
+ if os.environ.get('XDG_SESSION_TYPE') == "wayland":
38
+ self.platform = "linux_wayland"
39
+ else:
40
+ self.platform = "linux_x"
41
+
42
+ case ("Darwin"):
43
+ self.platform = "mac"
44
+
45
+ case ("Windows"):
46
+ self.platform = "windows"
47
+
48
+ return self.platform
49
+
50
+
51
+ def get_idle_seconds_linux_wayland (self):
52
+ # https://askubuntu.com/a/1231995/292055
53
+
54
+ command = "dbus-send --print-reply --dest=org.gnome.Mutter.IdleMonitor /org/gnome/Mutter/IdleMonitor/Core org.gnome.Mutter.IdleMonitor.GetIdletime"
55
+
56
+ response = subprocess.getoutput(command)
57
+
58
+ idle_time = int(int(response.rsplit(None,1)[-1]) / 1000)
59
+
60
+ return idle_time
61
+
62
+
63
+ def get_idle_seconds_linux_x (self):
64
+ idle_time = int(subprocess.getoutput('xprintidle')) / 1000 # Requires xprintidle (sudo apt install xprintidle)
65
+ return idle_time
66
+
67
+
68
+ def get_idle_seconds_windows (self):
69
+ # https://stackoverflow.com/a/67091943/4692205
70
+ import win32api
71
+
72
+ idle_time = (win32api.GetTickCount() - win32api.GetLastInputInfo()) / 1000.0
73
+
74
+ return idle_time
75
+
76
+
77
+ def get_idle_seconds_mac (self):
78
+ # https://stackoverflow.com/a/17966890/4692205
79
+ command = "ioreg -c IOHIDSystem | awk '/HIDIdleTime/ {print $NF/1000000000; exit}'"
80
+
81
+ idle_time = int(float(subprocess.getoutput(command)))
82
+ return idle_time