nowfocus 0.4.2__tar.gz → 0.5.0__tar.gz
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-0.4.2/src/nowfocus.egg-info → nowfocus-0.5.0}/PKG-INFO +2 -10
- {nowfocus-0.4.2 → nowfocus-0.5.0}/README.md +1 -9
- {nowfocus-0.4.2 → nowfocus-0.5.0}/pyproject.toml +1 -8
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/__main__.py +158 -146
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/conf.py +42 -49
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/desktop-extras/nowfocus.desktop +1 -1
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/example-todo.txt +1 -2
- nowfocus-0.5.0/src/nowfocus/install.py +92 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/session_options.py +1 -1
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/task_window.py +6 -6
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/utils.py +81 -82
- nowfocus-0.5.0/src/nowfocus/version_migrator.py +20 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0/src/nowfocus.egg-info}/PKG-INFO +2 -10
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus.egg-info/SOURCES.txt +2 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/LICENSE +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/setup.cfg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/__init__.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/activitywatch.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/caldav.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/csv.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/psc_timetracker.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/taskwarrior.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/timewarrior.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/todo_template.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/todotxt.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/trello.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/txt.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/connectors/vikunja.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/desktop-extras/nowfocus.png +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/desktop-extras/nowfocus.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/cancel.png +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/cancel.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/edit.png +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/edit.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-0.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-1.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-2.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-3.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-4.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-5.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-6.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-7.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-8.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-9.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon-red.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/icon.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/mark-done.png +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/mark-done.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/pause.png +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/pause.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/settings.png +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/icon/settings.svg +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/new_task_dialog.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/session_edit_dialog.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/sessions.csv +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/settings.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/sound/bell-xylophone-g.mp3 +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/sound/dinner-bell.mp3 +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/sound/xylophone-chord.mp3 +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/styles.css +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus/user_idle_time.py +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus.egg-info/dependency_links.txt +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus.egg-info/entry_points.txt +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus.egg-info/requires.txt +0 -0
- {nowfocus-0.4.2 → nowfocus-0.5.0}/src/nowfocus.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nowfocus
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: nowfocus: the open source task-tracking self-control panel.
|
|
5
5
|
Author: AltruistEnterprises
|
|
6
6
|
Project-URL: Homepage, https://www.nowfocus.org
|
|
@@ -112,13 +112,6 @@ nowfocus is a clean, keyboard-driven time management dashboard that flexibly con
|
|
|
112
112
|
# Install nowfocus
|
|
113
113
|
pipx install nowfocus
|
|
114
114
|
|
|
115
|
-
# Enter application directory
|
|
116
|
-
cd ~/.local/share/pipx/venvs/nowfocus/lib/python3.12/site-packages/nowfocus/desktop-extras
|
|
117
|
-
|
|
118
|
-
# Copy desktop file and icon to /usr/share
|
|
119
|
-
sudo cp nowfocus.desktop /usr/share/applications/nowfocus.desktop
|
|
120
|
-
sudo cp nowfocus.svg /usr/share/icons/hicolor/scalable/apps/nowfocus.svg
|
|
121
|
-
|
|
122
115
|
# and now Focus!
|
|
123
116
|
nowfocus
|
|
124
117
|
|
|
@@ -130,7 +123,6 @@ nowfocus is a clean, keyboard-driven time management dashboard that flexibly con
|
|
|
130
123
|
```
|
|
131
124
|
|
|
132
125
|
|
|
133
|
-
|
|
134
126
|
3. Add the following command to your startup applications:
|
|
135
127
|
```
|
|
136
128
|
nowfocus --force
|
|
@@ -178,7 +170,7 @@ Open nowfocus **Settings** from the indicator menu or tasks window and connect y
|
|
|
178
170
|
|
|
179
171
|
### Install From Source
|
|
180
172
|
```
|
|
181
|
-
git clone https://codeberg.org/AltruistEnterprises/nowfocus
|
|
173
|
+
git clone https://codeberg.org/AltruistEnterprises/nowfocus.git
|
|
182
174
|
cd nowfocus
|
|
183
175
|
python3 -m venv .venv/nowfocus-build
|
|
184
176
|
source .venv/nowfocus-build/bin/activate
|
|
@@ -69,13 +69,6 @@ nowfocus is a clean, keyboard-driven time management dashboard that flexibly con
|
|
|
69
69
|
# Install nowfocus
|
|
70
70
|
pipx install nowfocus
|
|
71
71
|
|
|
72
|
-
# Enter application directory
|
|
73
|
-
cd ~/.local/share/pipx/venvs/nowfocus/lib/python3.12/site-packages/nowfocus/desktop-extras
|
|
74
|
-
|
|
75
|
-
# Copy desktop file and icon to /usr/share
|
|
76
|
-
sudo cp nowfocus.desktop /usr/share/applications/nowfocus.desktop
|
|
77
|
-
sudo cp nowfocus.svg /usr/share/icons/hicolor/scalable/apps/nowfocus.svg
|
|
78
|
-
|
|
79
72
|
# and now Focus!
|
|
80
73
|
nowfocus
|
|
81
74
|
|
|
@@ -87,7 +80,6 @@ nowfocus is a clean, keyboard-driven time management dashboard that flexibly con
|
|
|
87
80
|
```
|
|
88
81
|
|
|
89
82
|
|
|
90
|
-
|
|
91
83
|
3. Add the following command to your startup applications:
|
|
92
84
|
```
|
|
93
85
|
nowfocus --force
|
|
@@ -135,7 +127,7 @@ Open nowfocus **Settings** from the indicator menu or tasks window and connect y
|
|
|
135
127
|
|
|
136
128
|
### Install From Source
|
|
137
129
|
```
|
|
138
|
-
git clone https://codeberg.org/AltruistEnterprises/nowfocus
|
|
130
|
+
git clone https://codeberg.org/AltruistEnterprises/nowfocus.git
|
|
139
131
|
cd nowfocus
|
|
140
132
|
python3 -m venv .venv/nowfocus-build
|
|
141
133
|
source .venv/nowfocus-build/bin/activate
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "nowfocus"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.5.0"
|
|
4
4
|
authors = [
|
|
5
5
|
{ name="AltruistEnterprises" },
|
|
6
6
|
]
|
|
@@ -22,15 +22,10 @@ dependencies = [
|
|
|
22
22
|
"psutil",
|
|
23
23
|
"pygobject == 3.50.0",
|
|
24
24
|
"pycairo == 1.27",
|
|
25
|
-
# "meson",
|
|
26
|
-
# "meson-python",
|
|
27
25
|
"attrs",
|
|
28
26
|
"caldav",
|
|
29
27
|
"certifi",
|
|
30
28
|
"charset-normalizer",
|
|
31
|
-
# "dbus-idle",
|
|
32
|
-
# "dbus-python",
|
|
33
|
-
# "jeepney",
|
|
34
29
|
"icalendar",
|
|
35
30
|
"idna",
|
|
36
31
|
"pywin32>=221 ; platform_system == 'Windows'",
|
|
@@ -56,12 +51,10 @@ dependencies = [
|
|
|
56
51
|
[project.urls]
|
|
57
52
|
Homepage = "https://www.nowfocus.org"
|
|
58
53
|
repository = "https://codeberg.org/AltruistEnterprises/nowfocus"
|
|
59
|
-
# Homepage = "https://gitlab.com/GitFr33/nowfocus"
|
|
60
54
|
|
|
61
55
|
[project.gui-scripts]
|
|
62
56
|
nowfocus = "nowfocus.__main__:startup"
|
|
63
57
|
|
|
64
|
-
|
|
65
58
|
# include non .py files in the dist
|
|
66
59
|
[tool.setuptools.packages.find]
|
|
67
60
|
where = ["src"]
|
|
@@ -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
|
|
|
@@ -62,81 +60,59 @@ class Application(Gtk.Application):
|
|
|
62
60
|
def __init__(self, *args, **kwargs):
|
|
63
61
|
super().__init__(*args, application_id="org.nowfocus.nowfocus", **kwargs)
|
|
64
62
|
|
|
65
|
-
|
|
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.
|
|
63
|
+
try:
|
|
68
64
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
# return None
|
|
73
|
-
|
|
74
|
-
self.window = None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
self.window = None
|
|
75
68
|
|
|
76
|
-
|
|
77
|
-
|
|
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()
|
|
78
74
|
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
self.menu = Gtk.Menu()
|
|
76
|
+
self.menu_tasks = {}
|
|
77
|
+
self.list_menus = {}
|
|
81
78
|
|
|
82
|
-
|
|
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)
|
|
83
82
|
|
|
84
|
-
|
|
83
|
+
if conf.is_first_load:
|
|
84
|
+
import install
|
|
85
|
+
install.run_first_load_actions()
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
# menu.set_reserve_toggle_size(False) # skip menu left padding, doesn't work
|
|
87
|
+
utils.db_schema_update()
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
utils.db_schema_update()
|
|
89
|
+
self.async_refresh()
|
|
91
90
|
|
|
91
|
+
# utils.db_cleanup()
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
self.async_refresh()
|
|
93
|
+
main_tick_timer = GLib.timeout_add_seconds(1, self.tick)
|
|
95
94
|
|
|
96
|
-
|
|
95
|
+
self.resume_session_from_db()
|
|
97
96
|
|
|
98
|
-
|
|
97
|
+
self.start_pipe()
|
|
98
|
+
self.open_task_window()
|
|
99
99
|
|
|
100
|
-
|
|
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()
|
|
101
106
|
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
signal.signal(signal.SIGINT, self.quit)
|
|
108
|
+
signal.signal(signal.SIGUSR1, self.signal_handler)
|
|
109
|
+
signal.signal(signal.SIGUSR2, self.signal_handler)
|
|
104
110
|
|
|
105
|
-
|
|
106
|
-
s = json.loads(db_session[0]['value'])
|
|
107
|
-
s['start_time'] = datetime.strptime(s['start_time'],'%Y-%m-%d %H:%M:%S.%f')
|
|
108
|
-
self.session = s
|
|
109
|
-
self.is_running = True
|
|
110
|
-
dbg("resuming session",s['label'],l=2, s='session')
|
|
111
|
+
Gtk.main()
|
|
111
112
|
except Exception as e:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
self.pipethread = threading.Thread(target=self.check_pipe)
|
|
117
|
-
self.pipethread.daemon = True
|
|
118
|
-
self.pipethread.start()
|
|
119
|
-
|
|
120
|
-
# Testing
|
|
121
|
-
# time.sleep(3)
|
|
122
|
-
# self.open_session_options_dialog('test_param')
|
|
123
|
-
|
|
124
|
-
# self.open_settings_window() #for testing
|
|
125
|
-
# self.open_task_window() #for testing
|
|
126
|
-
|
|
127
|
-
# time.sleep(2)
|
|
128
|
-
# self.open_new_task_dialog() #for testing
|
|
129
|
-
|
|
130
|
-
# time.sleep(2)
|
|
131
|
-
# self.print_time_totals()
|
|
132
|
-
|
|
133
|
-
# signal.signal(signal.SIGINT, signal.SIG_DFL)
|
|
134
|
-
signal.signal(signal.SIGINT, self.quit)
|
|
135
|
-
signal.signal(signal.SIGUSR1, self.signal_handler)
|
|
136
|
-
signal.signal(signal.SIGUSR2, self.signal_handler)
|
|
137
|
-
|
|
138
|
-
Gtk.main()
|
|
139
|
-
|
|
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()
|
|
140
116
|
|
|
141
117
|
|
|
142
118
|
def print_time_totals(self = None, widget = None):
|
|
@@ -177,25 +153,13 @@ class Application(Gtk.Application):
|
|
|
177
153
|
exit()
|
|
178
154
|
|
|
179
155
|
|
|
180
|
-
def
|
|
181
|
-
|
|
182
|
-
|
|
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()
|
|
183
161
|
|
|
184
|
-
|
|
185
|
-
# Requires xprintidle (sudo apt install xprintidle)
|
|
186
|
-
# idle_time = int(int(subprocess.getoutput('xprintidle')) / 1000)
|
|
187
|
-
|
|
188
|
-
# Version that works, using: https://github.com/bkbilly/dbus_idle
|
|
189
|
-
# but has many deps
|
|
190
|
-
# Requires:
|
|
191
|
-
# sudo apt install meson libdbus-glib-1-dev patchelf
|
|
192
|
-
# pip install dbus-idle
|
|
193
|
-
|
|
194
|
-
# idle_time = int(int(IdleMonitor().get_dbus_idle()) / 1000)
|
|
195
|
-
# return idle_time
|
|
196
|
-
|
|
197
|
-
return self.UserIdleTime.get()
|
|
198
|
-
|
|
162
|
+
return self.seconds_since_user_active
|
|
199
163
|
|
|
200
164
|
|
|
201
165
|
def toggle_do_not_disturb(self, widget):
|
|
@@ -213,81 +177,106 @@ class Application(Gtk.Application):
|
|
|
213
177
|
|
|
214
178
|
def tock(self):
|
|
215
179
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
afk_time = self.seconds_since_user_active()
|
|
220
|
-
# 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))
|
|
221
182
|
|
|
222
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 )
|
|
223
184
|
|
|
224
|
-
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
|
|
225
187
|
self.async_refresh()
|
|
226
188
|
|
|
227
|
-
# TODO: use individual todo_refresh_times
|
|
228
|
-
|
|
229
189
|
minutes = (int(self.session['duration']) / 60)
|
|
230
190
|
|
|
231
|
-
if
|
|
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
|
+
|
|
232
210
|
|
|
233
|
-
if
|
|
234
|
-
|
|
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()
|
|
226
|
+
|
|
227
|
+
playsound('sound/xylophone-chord.mp3',False)
|
|
228
|
+
|
|
229
|
+
elif num_is_multiple_of(minutes,conf.user['randomness_interrupt_interval']):
|
|
235
230
|
|
|
236
|
-
|
|
231
|
+
notify.Notification.new("What Am I doing?","Your randomness timer is at "+str(minutes)+" minutes. ", None).show()
|
|
237
232
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
233
|
+
self.open_task_window()
|
|
234
|
+
|
|
235
|
+
playsound('sound/dinner-bell.mp3',False)
|
|
241
236
|
|
|
242
|
-
elif afk_time > 120:
|
|
243
|
-
self.session['duration'] = 0
|
|
244
|
-
self.session['start_time'] = now()
|
|
245
|
-
print("Idle time reset. afk:", afk_time, self.session)
|
|
246
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
|
|
247
243
|
else:
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if afk_time < 181:
|
|
251
|
-
self.open_task_window(None,{'afk_time':afk_time})
|
|
252
|
-
else:
|
|
253
|
-
if self.session['label'] in conf.user['custom_pomodoro_intervals']:
|
|
254
|
-
check = conf.user['custom_pomodoro_intervals'][self.session['label']]
|
|
255
|
-
else:
|
|
256
|
-
check = conf.user['pomodoro_interval']
|
|
257
|
-
|
|
258
|
-
if float(minutes / check ).is_integer():
|
|
259
|
-
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
|
|
260
246
|
|
|
261
|
-
playsound('sound/bell-xylophone-g.mp3',False)
|
|
262
247
|
|
|
248
|
+
def handle_device_became_inactive(self):
|
|
249
|
+
self.user_last_inactive = now()
|
|
263
250
|
|
|
264
|
-
|
|
265
|
-
|
|
251
|
+
user_inactive_time = self.get_seconds_since_user_active()
|
|
252
|
+
dbg('device_became_inactive ',l=-1)
|
|
266
253
|
|
|
267
|
-
|
|
268
|
-
print("At", t['percent'], "% of ", t['scope'], " target")
|
|
254
|
+
if self.is_running and 'do-not-disturb' not in self.session:
|
|
269
255
|
|
|
270
|
-
|
|
271
|
-
if t['percent'] >= 100:
|
|
256
|
+
self.open_task_window(None,{'user_inactive_time':user_inactive_time})
|
|
272
257
|
|
|
273
|
-
|
|
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)
|
|
262
|
+
|
|
263
|
+
self.session['duration'] = 0
|
|
264
|
+
self.session['start_time'] = now()
|
|
265
|
+
dbg("Recording:", user_inactive_time, self.session)
|
|
266
|
+
|
|
267
|
+
if 'do-not-disturb' not in self.session and conf.user['randomness_interrupt_interval'] > 0:
|
|
268
|
+
self.open_task_window(None)
|
|
274
269
|
|
|
275
|
-
playsound('sound/dinner-bell.mp3',False)
|
|
276
270
|
|
|
277
|
-
elif t['type'] == 'min' and round(t['starting_value'] + minutes) == t['value']:
|
|
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()
|
|
279
|
-
|
|
280
|
-
playsound('sound/xylophone-chord.mp3',False)
|
|
281
|
-
|
|
282
|
-
|
|
283
271
|
def tick(self):
|
|
284
272
|
|
|
285
273
|
# check for suspend indicated by gap in tick intervals
|
|
286
274
|
time_since_last_tick = round(time_difference(self.session['start_time']) - self.session['duration'])
|
|
287
275
|
if time_since_last_tick > 10:
|
|
276
|
+
|
|
288
277
|
dbg(time_since_last_tick, " seconds since last tick. Probably just woke from suspend. ")
|
|
289
278
|
if self.is_running:
|
|
290
|
-
self.open_task_window(None,{'
|
|
279
|
+
self.open_task_window(None,{'user_inactive_time':time_since_last_tick})
|
|
291
280
|
else:
|
|
292
281
|
self.session['start_time'] = now()
|
|
293
282
|
|
|
@@ -312,7 +301,6 @@ class Application(Gtk.Application):
|
|
|
312
301
|
|
|
313
302
|
if duration > 60 and num_is_multiple_of(duration, 2):
|
|
314
303
|
icon = 'icon-red.svg'
|
|
315
|
-
|
|
316
304
|
else:
|
|
317
305
|
icon = 'icon-1.svg'
|
|
318
306
|
|
|
@@ -321,13 +309,28 @@ class Application(Gtk.Application):
|
|
|
321
309
|
self.indicator.set_icon_full(os.path.abspath('icon/'+icon),label)
|
|
322
310
|
self.indicator.set_label(label,label)
|
|
323
311
|
|
|
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")
|
|
324
321
|
|
|
325
|
-
if num_is_multiple_of(self.icon_tick_number,3):
|
|
326
|
-
self.refresh_all_changed_todo_files()
|
|
327
|
-
|
|
328
322
|
return True
|
|
329
323
|
|
|
330
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
|
+
|
|
331
334
|
def refresh_all_changed_todo_files(self):
|
|
332
335
|
for id, todo_config in conf.user['todolists'].items():
|
|
333
336
|
if todo_config['status'] and 'watch_file' in todo_config:
|
|
@@ -352,6 +355,20 @@ class Application(Gtk.Application):
|
|
|
352
355
|
handle_todo_read_error(todo_config,e)
|
|
353
356
|
|
|
354
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
|
+
|
|
355
372
|
def start_task(self, w = None, task_data_or_id = None, transfer_current_session_time = False):
|
|
356
373
|
|
|
357
374
|
if isinstance(task_data_or_id, dict):
|
|
@@ -420,7 +437,7 @@ class Application(Gtk.Application):
|
|
|
420
437
|
self.task_running_menu_additions()
|
|
421
438
|
|
|
422
439
|
self.menu.show_all()
|
|
423
|
-
|
|
440
|
+
dbg("Starting",task_data['extended_label'])
|
|
424
441
|
|
|
425
442
|
if task_data['id'] in conf.user['task_commands']:
|
|
426
443
|
command_data = conf.user['task_commands'][task_data['id']]
|
|
@@ -431,7 +448,7 @@ class Application(Gtk.Application):
|
|
|
431
448
|
|
|
432
449
|
|
|
433
450
|
def run_task_command(self,command):
|
|
434
|
-
|
|
451
|
+
dbg("running task command:", command,l=-1)
|
|
435
452
|
|
|
436
453
|
self.running_command_task_label = copy.copy(self.session['label'])
|
|
437
454
|
|
|
@@ -736,24 +753,20 @@ class Application(Gtk.Application):
|
|
|
736
753
|
dbg('Signal received',sig,s='signals')
|
|
737
754
|
|
|
738
755
|
if sig == signal.SIGUSR1:
|
|
739
|
-
# try:
|
|
740
|
-
# print('TaskWindow._instance',TaskWindow._instance)
|
|
741
|
-
# if TaskWindow._instance:
|
|
742
|
-
# self.taskwindow.destroy()
|
|
743
|
-
# else:
|
|
744
|
-
# self.open_task_window()
|
|
745
|
-
|
|
746
|
-
# except AttributeError:
|
|
747
756
|
self.open_task_window()
|
|
748
|
-
|
|
749
757
|
elif sig == signal.SIGUSR2:
|
|
750
758
|
self.open_session_options_dialog()
|
|
751
|
-
|
|
752
759
|
else:
|
|
753
760
|
dbg("no handler for received signal",s='signals',l=3)
|
|
754
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
|
+
|
|
755
769
|
def check_pipe(self):
|
|
756
|
-
# print("Listening to pipe at ",conf.pipe)
|
|
757
770
|
|
|
758
771
|
try:
|
|
759
772
|
with open(conf.pipe, "r") as pipe:
|
|
@@ -823,7 +836,6 @@ def startup():
|
|
|
823
836
|
except Exception as e:
|
|
824
837
|
print(e)
|
|
825
838
|
|
|
826
|
-
|
|
827
839
|
try:
|
|
828
840
|
os.mkfifo(conf.pipe)
|
|
829
841
|
dbg("Named pipe created successfully!", s="cli")
|
|
@@ -839,7 +851,7 @@ def startup():
|
|
|
839
851
|
|
|
840
852
|
|
|
841
853
|
except FileExistsError:
|
|
842
|
-
|
|
854
|
+
print("Named pipe exists, application must be running (or improperly shut down.) ")
|
|
843
855
|
|
|
844
856
|
# if args: pass to pipe and exit
|
|
845
857
|
if args.task:
|