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 +89 -83
- nowfocus/conf.py +4 -5
- nowfocus/connectors/todotxt.py +8 -3
- nowfocus/connectors/txt.py +14 -2
- nowfocus/connectors/vikunja.py +16 -17
- nowfocus/new_task_dialog.py +3 -4
- nowfocus/settings.py +10 -51
- nowfocus/styles.css +9 -11
- nowfocus/task_window.py +125 -66
- nowfocus/user_idle_time.py +82 -0
- nowfocus/utils.py +231 -127
- {nowfocus-0.2.13.dist-info → nowfocus-0.4.2.dist-info}/METADATA +26 -24
- {nowfocus-0.2.13.dist-info → nowfocus-0.4.2.dist-info}/RECORD +17 -16
- {nowfocus-0.2.13.dist-info → nowfocus-0.4.2.dist-info}/WHEEL +0 -0
- {nowfocus-0.2.13.dist-info → nowfocus-0.4.2.dist-info}/entry_points.txt +0 -0
- {nowfocus-0.2.13.dist-info → nowfocus-0.4.2.dist-info}/licenses/LICENSE +0 -0
- {nowfocus-0.2.13.dist-info → nowfocus-0.4.2.dist-info}/top_level.txt +0 -0
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
16
|
+
.subtle{
|
|
24
17
|
font-weight: 100;
|
|
25
18
|
font-size:16px;
|
|
26
|
-
opacity: .
|
|
19
|
+
opacity: .4;
|
|
27
20
|
}
|
|
28
21
|
|
|
29
|
-
|
|
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,48 @@ class TaskWindow(Gtk.Window):
|
|
|
67
70
|
self.shown_tasks = {}
|
|
68
71
|
|
|
69
72
|
self.set_border_width(20)
|
|
70
|
-
self.set_position(position=1)
|
|
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
|
-
|
|
76
|
-
|
|
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.
|
|
81
|
+
self.l_sidebar = Gtk.VBox(spacing=5)
|
|
82
|
+
self.l_sidebar.get_style_context().add_class("subtle")
|
|
83
|
+
self.outer_box.add(self.l_sidebar)
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
self.center_box = Gtk.VBox(spacing=10)
|
|
86
|
+
self.center_box.set_halign(Gtk.Align.CENTER)
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
self.outer_box.add(self.center_box)
|
|
89
|
+
|
|
90
|
+
self.header = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=15, border_width=10)
|
|
86
91
|
|
|
92
|
+
self.center_box.pack_start(self.header,False, False, 0)
|
|
93
|
+
|
|
87
94
|
self.recreate_header()
|
|
88
95
|
|
|
96
|
+
|
|
97
|
+
self.r_sidebar = Gtk.VBox(spacing=5)
|
|
98
|
+
self.r_sidebar.get_style_context().add_class("subtle")
|
|
99
|
+
self.outer_box.add(self.r_sidebar)
|
|
100
|
+
|
|
101
|
+
|
|
89
102
|
self.tick_timer = GLib.timeout_add_seconds(1, self.tick)
|
|
90
103
|
|
|
91
104
|
self.task_entry_overlay = Gtk.Overlay()
|
|
92
105
|
|
|
93
|
-
# Large fuzzy task input
|
|
94
106
|
self.taskEntry = Gtk.Entry()
|
|
95
|
-
self.taskEntry.set_name("FuzzyTask")
|
|
96
|
-
# self.taskEntry.set_width_chars(59)
|
|
107
|
+
self.taskEntry.set_name("FuzzyTask")
|
|
97
108
|
self.taskEntry.set_max_width_chars(79)
|
|
98
|
-
|
|
99
109
|
self.taskEntry.set_placeholder_text("Find Task [Ctrl+F]")
|
|
100
110
|
self.taskEntry.set_property("tooltip-text", "Find Task [Ctrl+F], press Enter to start work on the first task in the list")
|
|
101
111
|
|
|
102
112
|
self.task_entry_overlay.add(self.taskEntry)
|
|
103
113
|
|
|
104
|
-
|
|
114
|
+
self.center_box.pack_start(self.task_entry_overlay,False, False, 0)
|
|
105
115
|
|
|
106
116
|
self.taskEntry.grab_focus()
|
|
107
117
|
|
|
@@ -126,10 +136,9 @@ class TaskWindow(Gtk.Window):
|
|
|
126
136
|
self.taskEntry.set_text(passed_data['task']['label'])
|
|
127
137
|
|
|
128
138
|
|
|
129
|
-
|
|
130
139
|
self.scrolled_window = Gtk.ScrolledWindow()
|
|
131
140
|
self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
|
132
|
-
|
|
141
|
+
self.center_box.pack_start(self.scrolled_window, True, True, 0)
|
|
133
142
|
self.scrolled_window.set_size_request(-1, 350)
|
|
134
143
|
|
|
135
144
|
self.scrolled_window.connect('scroll-event', self.on_scroll) # This doesn't catch scrollbar moves
|
|
@@ -142,6 +151,7 @@ class TaskWindow(Gtk.Window):
|
|
|
142
151
|
|
|
143
152
|
self.total_duration_label = Gtk.Label()
|
|
144
153
|
self.total_duration_label.set_margin_end(12)
|
|
154
|
+
self.total_duration_label.get_style_context().add_class('subtle')
|
|
145
155
|
self.total_duration_label.set_halign(Gtk.Align.END)
|
|
146
156
|
self.task_entry_overlay.add_overlay(self.total_duration_label)
|
|
147
157
|
|
|
@@ -156,14 +166,14 @@ class TaskWindow(Gtk.Window):
|
|
|
156
166
|
# self.timesheet_to_button.connect("clicked",self.timesheet_to_clipboard)
|
|
157
167
|
# self.timesheet_to_button.set_name("Footer")
|
|
158
168
|
# self.timesheet_to_button.set_property("tooltip-text","Click to copy CSV timesheet to clipboard")
|
|
159
|
-
#
|
|
169
|
+
# self.center_box.pack_start(self.timesheet_to_button,False, False, 0)
|
|
160
170
|
|
|
161
171
|
|
|
162
172
|
self.buttons_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20)
|
|
163
173
|
self.buttons_box.set_halign(Gtk.Align.CENTER)
|
|
164
|
-
self.buttons_box.
|
|
174
|
+
self.buttons_box.get_style_context().add_class("subtle")
|
|
165
175
|
|
|
166
|
-
|
|
176
|
+
self.center_box.pack_start(self.buttons_box,False, False, 0)
|
|
167
177
|
|
|
168
178
|
self.settings_button = Gtk.Button(label="Settings")
|
|
169
179
|
self.settings_button.connect("clicked",self.app.open_settings_window)
|
|
@@ -181,7 +191,8 @@ class TaskWindow(Gtk.Window):
|
|
|
181
191
|
openable = conf.todo_connectors[todo['type']].launch
|
|
182
192
|
openable_button = Gtk.Button(label=GLib.markup_escape_text(todo['label']))
|
|
183
193
|
openable_button.connect("clicked", lambda button_widget,todo=todo, openable=openable: openable(todo))
|
|
184
|
-
openable_button.set_property("tooltip-text","Open
|
|
194
|
+
openable_button.set_property("tooltip-text","Open "+GLib.markup_escape_text(todo['label']))
|
|
195
|
+
|
|
185
196
|
self.buttons_box.add(openable_button)
|
|
186
197
|
|
|
187
198
|
except Exception as e:
|
|
@@ -193,6 +204,8 @@ class TaskWindow(Gtk.Window):
|
|
|
193
204
|
self.buttons_box.add(self.new_task_button)
|
|
194
205
|
|
|
195
206
|
self.show_all()
|
|
207
|
+
timeit()
|
|
208
|
+
|
|
196
209
|
|
|
197
210
|
key, mod = Gtk.accelerator_parse('<Control>n')
|
|
198
211
|
self.new_task_button.add_accelerator("clicked", self.accel_group, key, mod, Gtk.AccelFlags.VISIBLE)
|
|
@@ -205,11 +218,18 @@ class TaskWindow(Gtk.Window):
|
|
|
205
218
|
self.connect("window-state-event", self.on_window_state_event)
|
|
206
219
|
|
|
207
220
|
self.taskEntry.connect("changed",self.task_search)
|
|
221
|
+
GLib.idle_add(self.refresh_search_cache)
|
|
208
222
|
|
|
209
|
-
self.refresh_search_cache()
|
|
210
223
|
self.connect("destroy", self.on_destroy)
|
|
211
224
|
|
|
212
|
-
|
|
225
|
+
|
|
226
|
+
def test(self=None, one=None, two=None, **kwargs):
|
|
227
|
+
print('task_window test')
|
|
228
|
+
print(one)
|
|
229
|
+
print(two)
|
|
230
|
+
print(kwargs)
|
|
231
|
+
|
|
232
|
+
|
|
213
233
|
def on_destroy(self, widget= None):
|
|
214
234
|
TaskWindow._instance = None
|
|
215
235
|
print("¡Adios Task Window!")
|
|
@@ -221,11 +241,15 @@ class TaskWindow(Gtk.Window):
|
|
|
221
241
|
if self.lazy_loadable_tasks:
|
|
222
242
|
print('Tasks to lazy load ', len(self.lazy_loadable_tasks))
|
|
223
243
|
for id, t in self.lazy_loadable_tasks.items():
|
|
224
|
-
self.
|
|
244
|
+
self.add_task_to_window(t)
|
|
225
245
|
self.tasks_box.show_all()
|
|
226
246
|
|
|
227
247
|
self.lazy_loadable_tasks = {}
|
|
228
248
|
|
|
249
|
+
def select_list_callback(self, widget, l):
|
|
250
|
+
print('widget',widget,'list',l)
|
|
251
|
+
self.taskEntry.set_text(l['extended_label']+" > ")
|
|
252
|
+
self.taskEntry.grab_focus()
|
|
229
253
|
|
|
230
254
|
def refresh_search_cache(self,w = None):
|
|
231
255
|
self.search_cache = {}
|
|
@@ -242,13 +266,11 @@ class TaskWindow(Gtk.Window):
|
|
|
242
266
|
|
|
243
267
|
self.session_time.set_label(sec_to_time(self.app.session['duration']))
|
|
244
268
|
if self.app.session['label'] != self.header_task:
|
|
245
|
-
self.recreate_header()
|
|
269
|
+
self.recreate_header()
|
|
246
270
|
|
|
247
271
|
if utils.taskindex_updated_time() > self.search_cache_refresh_time:
|
|
248
272
|
# print("taskindex was updated, utils.taskindex_updated_time()", utils.taskindex_updated_time(), 'self.search_cache_refresh_time',self.search_cache_refresh_time)
|
|
249
273
|
self.refresh_search_cache()
|
|
250
|
-
# else:
|
|
251
|
-
# print("taskindex was not updated",current_data_version)
|
|
252
274
|
|
|
253
275
|
return True # This continues the timer
|
|
254
276
|
|
|
@@ -349,12 +371,57 @@ class TaskWindow(Gtk.Window):
|
|
|
349
371
|
|
|
350
372
|
|
|
351
373
|
self.header.show_all()
|
|
374
|
+
GLib.idle_add(self.create_sidebars)
|
|
352
375
|
|
|
353
376
|
try:
|
|
354
377
|
self.taskEntry.grab_focus()
|
|
355
378
|
except Exception:
|
|
356
379
|
pass
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def create_sidebars(self):
|
|
383
|
+
timeit()
|
|
357
384
|
|
|
385
|
+
self.l_sidebar.foreach(lambda child: child.destroy())
|
|
386
|
+
self.r_sidebar.foreach(lambda child: child.destroy())
|
|
387
|
+
|
|
388
|
+
if conf.user['open_task_window_fullscreen'] and conf.user['show_task_window_sidebars']:
|
|
389
|
+
self.l_sidebar.set_size_request(350, -1)
|
|
390
|
+
self.r_sidebar.set_size_request(350, -1)
|
|
391
|
+
|
|
392
|
+
focus_percent_label = Gtk.Label()
|
|
393
|
+
focus_percent_label.set_markup("<b>Focus: "+str(utils.get_percent_time_focused())+"%</b>")
|
|
394
|
+
self.r_sidebar.pack_start(focus_percent_label, False, True, 25)
|
|
395
|
+
|
|
396
|
+
self.sessions_scrolledwindow = Gtk.ScrolledWindow()
|
|
397
|
+
self.sessions_scrolledwindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
|
398
|
+
self.r_sidebar.pack_start(self.sessions_scrolledwindow, True, True, 0)
|
|
399
|
+
|
|
400
|
+
self.sessions_box = Gtk.VBox(spacing=5)
|
|
401
|
+
# self.sessions_box.get_style_context().add_class("subtle")
|
|
402
|
+
self.sessions_scrolledwindow.add(self.sessions_box)
|
|
403
|
+
|
|
404
|
+
# self.r_sidebar.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK)
|
|
405
|
+
# self.r_sidebar.add_events(Gdk.EventMask.LEAVE_NOTIFY_MASK)
|
|
406
|
+
# self.r_sidebar.connect("enter-notify-event",self.test)
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
self.l_sidebar.add(choose_from_lists(self.select_list_callback, 'None', None, False))
|
|
410
|
+
|
|
411
|
+
self.SessionEditDialog = SessionEditDialog # passed to show_sessions
|
|
412
|
+
show_sessions(None, self, self.sessions_box, None, 'start_time', '30',None, 30)
|
|
413
|
+
|
|
414
|
+
self.l_sidebar.show_all()
|
|
415
|
+
self.r_sidebar.show_all()
|
|
416
|
+
else:
|
|
417
|
+
self.r_sidebar.set_size_request(-1, -1)
|
|
418
|
+
self.l_sidebar.set_size_request(-1, -1)
|
|
419
|
+
|
|
420
|
+
self.l_sidebar.hide()
|
|
421
|
+
self.r_sidebar.hide()
|
|
422
|
+
timeit()
|
|
423
|
+
|
|
424
|
+
|
|
358
425
|
def on_notes_changed(self,buffer):
|
|
359
426
|
notes = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False)
|
|
360
427
|
self.app.session['notes'] = notes
|
|
@@ -367,20 +434,18 @@ class TaskWindow(Gtk.Window):
|
|
|
367
434
|
self.refresh_search_cache()
|
|
368
435
|
|
|
369
436
|
|
|
370
|
-
def task_search(self,widget):
|
|
437
|
+
def task_search(self,widget = None):
|
|
371
438
|
|
|
372
439
|
self.tasks_box.foreach(lambda child: child.destroy())
|
|
373
|
-
self.tasks_box.show_all()
|
|
374
440
|
self.shown_tasks.clear()
|
|
375
441
|
|
|
376
|
-
self.search_term =
|
|
442
|
+
self.search_term = self.taskEntry.get_text()
|
|
377
443
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
tasks = self.search_cache[i]
|
|
444
|
+
if self.search_term in self.search_cache:
|
|
445
|
+
tasks = self.search_cache[self.search_term]
|
|
381
446
|
else:
|
|
382
|
-
tasks = utils.taskindex_search(
|
|
383
|
-
self.search_cache[
|
|
447
|
+
tasks = utils.taskindex_search(self.search_term)
|
|
448
|
+
self.search_cache[self.search_term] = tasks
|
|
384
449
|
|
|
385
450
|
total_duration = 0
|
|
386
451
|
self.lazy_loadable_tasks = {}
|
|
@@ -388,12 +453,12 @@ class TaskWindow(Gtk.Window):
|
|
|
388
453
|
if tasks:
|
|
389
454
|
count = 0
|
|
390
455
|
for id, t in tasks.items():
|
|
391
|
-
count
|
|
456
|
+
count += 1
|
|
392
457
|
if 'duration' in t and t['duration']:
|
|
393
458
|
total_duration += int(t['duration'])
|
|
394
459
|
|
|
395
460
|
if count < self.num_initial_tasks:
|
|
396
|
-
self.
|
|
461
|
+
self.add_task_to_window(t)
|
|
397
462
|
else:
|
|
398
463
|
self.lazy_loadable_tasks[id] = t
|
|
399
464
|
|
|
@@ -402,34 +467,27 @@ class TaskWindow(Gtk.Window):
|
|
|
402
467
|
self.total_duration_label.set_markup('<b>'+str(round(total_duration / 60 / 60,1))+'</b> hrs\n'+conf.user['hours_search_timeframe'] )
|
|
403
468
|
|
|
404
469
|
|
|
405
|
-
|
|
406
|
-
def add_task_to_list(self,t):
|
|
470
|
+
def add_task_to_window(self,t):
|
|
407
471
|
|
|
408
472
|
try:
|
|
409
|
-
search_str = self.search_term
|
|
410
473
|
utils.dbg("add_task_to_list "+ str(t['extended_label']), "status",t['status'], s='taskwindow',l=3)
|
|
411
474
|
|
|
412
|
-
# self.shown_tasks[t['id']] = Gtk.Button() # Works but does not accept popovers
|
|
413
475
|
self.shown_tasks[t['id']] = Gtk.MenuButton(popover=self.task_rclick_menu)
|
|
414
|
-
self.shown_tasks[t['id']]
|
|
415
|
-
|
|
476
|
+
button = self.shown_tasks[t['id']]
|
|
477
|
+
button.set_halign(Gtk.Align.START)
|
|
478
|
+
button.set_hexpand(True)
|
|
416
479
|
|
|
417
480
|
label = Gtk.Label()
|
|
418
481
|
|
|
419
|
-
# button_context = self.shown_tasks[t['id']].get_style_context().add_class("large")
|
|
420
482
|
extended_label = GLib.markup_escape_text(t['extended_label'],)
|
|
421
483
|
|
|
422
|
-
# Truncate excessively long task labels
|
|
423
484
|
if len(extended_label) > 110:
|
|
424
485
|
extended_label = extended_label[:110]+"..."
|
|
425
486
|
|
|
426
|
-
if len(
|
|
427
|
-
|
|
428
|
-
# fts5 match highlighting, not that good because it highlights the whole word rather than the matching part...
|
|
429
|
-
# extended_label = extended_label.replace('[[',"<b>").replace(']]',"</b>")
|
|
487
|
+
if len(self.search_term) > 1:
|
|
430
488
|
|
|
431
|
-
extended_label = extended_label.replace(
|
|
432
|
-
extended_label = extended_label.replace(
|
|
489
|
+
extended_label = extended_label.replace(self.search_term,"<b>"+self.search_term+"</b>")
|
|
490
|
+
extended_label = extended_label.replace(self.search_term.capitalize(),"<b>"+self.search_term.capitalize()+"</b>") # Cheesy but kind of works
|
|
433
491
|
|
|
434
492
|
if "duration" in t and t['duration']:
|
|
435
493
|
extended_label += " ("+sec_to_time(t['duration'])+")"
|
|
@@ -437,28 +495,22 @@ class TaskWindow(Gtk.Window):
|
|
|
437
495
|
if t['id'] in conf.user['task_commands'] and conf.user['task_commands'][t['id']]['status']:
|
|
438
496
|
extended_label += " ["+GLib.markup_escape_text(conf.user['task_commands'][t['id']]['command'])+"]"
|
|
439
497
|
|
|
440
|
-
if t['priority']:
|
|
441
|
-
extended_label = str(t['priority']) +" "+ extended_label
|
|
442
498
|
|
|
443
499
|
if not t['status']:
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
label.set_markup('<s>'+extended_label+'</s>')
|
|
500
|
+
button.get_style_context().add_class("done")
|
|
501
|
+
extended_label = '<s>'+extended_label+'</s>'
|
|
447
502
|
|
|
448
503
|
elif t['priority'] > 0:
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
else:
|
|
452
|
-
label.set_markup(extended_label)
|
|
504
|
+
extended_label = str(t['priority']) +" "+ extended_label
|
|
505
|
+
button.get_style_context().add_class("bold")
|
|
453
506
|
|
|
454
|
-
|
|
507
|
+
label.set_markup(extended_label)
|
|
508
|
+
button.add(label)
|
|
455
509
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
self.
|
|
460
|
-
self.tasks_box.add(self.shown_tasks[t['id']])
|
|
461
|
-
self.tasks_box.show_all()
|
|
510
|
+
button.connect("button-release-event", self.select_task, t['id'])
|
|
511
|
+
button.connect("activate", self.select_task, None, t['id'])
|
|
512
|
+
button.set_relief(Gtk.ReliefStyle.NONE)
|
|
513
|
+
self.tasks_box.add(button)
|
|
462
514
|
|
|
463
515
|
|
|
464
516
|
except Exception as e:
|
|
@@ -493,8 +545,12 @@ class TaskWindow(Gtk.Window):
|
|
|
493
545
|
w.set_halign(Gtk.Align.START)
|
|
494
546
|
w.set_relief(Gtk.ReliefStyle.NONE)
|
|
495
547
|
w.connect('clicked',self.app.mark_done,t)
|
|
548
|
+
|
|
549
|
+
w.connect('clicked',lambda button, self: self.task_rclick_menu.hide(),self)
|
|
550
|
+
w.connect('clicked',lambda button, self, t: self.shown_tasks[t['id']].destroy(),self,t)
|
|
496
551
|
vbox.pack_start(w, True, True, 5)
|
|
497
552
|
|
|
553
|
+
|
|
498
554
|
# Reassign session/randomness to be on this task,
|
|
499
555
|
w = Gtk.Button(label="Reassign last "+ str(round((self.app.session['duration'] / 60),1))+" minutes to this task" )
|
|
500
556
|
w.set_halign(Gtk.Align.START)
|
|
@@ -589,11 +645,14 @@ class TaskWindow(Gtk.Window):
|
|
|
589
645
|
self.unfullscreen()
|
|
590
646
|
self.get_style_context().remove_class("large")
|
|
591
647
|
conf.user['open_task_window_fullscreen'] = False
|
|
648
|
+
self.create_sidebars()
|
|
592
649
|
|
|
593
650
|
else:
|
|
594
651
|
self.fullscreen()
|
|
595
652
|
self.get_style_context().add_class("large")
|
|
596
653
|
conf.user['open_task_window_fullscreen'] = True
|
|
654
|
+
self.create_sidebars()
|
|
655
|
+
|
|
597
656
|
|
|
598
657
|
utils.save_user_settings()
|
|
599
658
|
|
|
@@ -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
|