Skip to content

Commit d558d34

Browse files
committed
Fix notifications
The code for notifications was removed somewhere in the history. With this commit, notifications are expected to work as usual! Signed-off-by: Sharaf Zaman <sharafzaz121@gmail.com>
1 parent d9b2a55 commit d558d34

6 files changed

Lines changed: 272 additions & 1 deletion

File tree

data/org.gnome.hamster.gschema.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,20 @@
1818
then the activity belongs to the previous hamster day.
1919
</description>
2020
</key>
21+
22+
<key type="u" name="notify-interval-minutes">
23+
<default>15</default>
24+
<summary>After how many minutes to notify the user</summary>
25+
</key>
26+
27+
<key type="b" name="notifications-enabled">
28+
<default>false</default>
29+
<summary>Enable notifications</summary>
30+
</key>
31+
32+
<key type="b" name="notify-on-idle-enabled">
33+
<default>false</default>
34+
<summary>Send Notifications when no activity is set</summary>
35+
</key>
2136
</schema>
2237
</schemalist>

data/preferences.ui

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
<!-- Generated with glade 3.20.4 -->
33
<interface>
44
<requires lib="gtk+" version="3.10"/>
5+
<object class="GtkAdjustment" id="adjustment1">
6+
<property name="upper">100</property>
7+
<property name="step_increment">1</property>
8+
<property name="page_increment">10</property>
9+
</object>
510
<object class="GtkTextBuffer" id="autocomplete_tags"/>
611
<object class="GtkWindow" id="window">
712
<property name="can_focus">False</property>
@@ -40,6 +45,89 @@
4045
<property name="valign">start</property>
4146
<property name="orientation">vertical</property>
4247
<property name="spacing">8</property>
48+
<child>
49+
<object class="GtkBox" id="box1">
50+
<property name="can_focus">False</property>
51+
<property name="orientation">vertical</property>
52+
<child>
53+
<object class="GtkCheckButton" id="notifs-enabled-toggle">
54+
<property name="label" translatable="yes">Send notifications</property>
55+
<property name="visible">True</property>
56+
<property name="can_focus">True</property>
57+
<property name="receives_default">False</property>
58+
<property name="draw_indicator">True</property>
59+
</object>
60+
<packing>
61+
<property name="expand">False</property>
62+
<property name="fill">True</property>
63+
<property name="position">-1</property>
64+
</packing>
65+
</child>
66+
<child>
67+
<object class="GtkBox" id="notification-box">
68+
<property name="visible">True</property>
69+
<property name="can_focus">False</property>
70+
<property name="margin_left">20</property>
71+
<property name="orientation">vertical</property>
72+
<property name="spacing">2</property>
73+
<child>
74+
<object class="GtkLabel" id="label1">
75+
<property name="visible">True</property>
76+
<property name="can_focus">False</property>
77+
<property name="label" translatable="yes">Remind of current activity every: </property>
78+
</object>
79+
<packing>
80+
<property name="expand">False</property>
81+
<property name="fill">True</property>
82+
<property name="position">0</property>
83+
</packing>
84+
</child>
85+
<child>
86+
<object class="GtkScale" id="notify-interval-scale">
87+
<property name="visible">True</property>
88+
<property name="can_focus">True</property>
89+
<property name="adjustment">adjustment1</property>
90+
<property name="fill_level">120</property>
91+
<property name="round_digits">0</property>
92+
<property name="digits">0</property>
93+
<property name="value_pos">right</property>
94+
</object>
95+
<packing>
96+
<property name="expand">False</property>
97+
<property name="fill">True</property>
98+
<property name="position">1</property>
99+
</packing>
100+
</child>
101+
<child>
102+
<object class="GtkCheckButton" id="notify-on-idle">
103+
<property name="label" translatable="yes">Also remind when no activity is set</property>
104+
<property name="visible">True</property>
105+
<property name="can_focus">True</property>
106+
<property name="receives_default">False</property>
107+
<property name="draw_indicator">True</property>
108+
<signal name="toggled" handler="_notify_on_idle_toggled" swapped="no"/>
109+
</object>
110+
<packing>
111+
<property name="expand">False</property>
112+
<property name="fill">True</property>
113+
<property name="position">2</property>
114+
</packing>
115+
</child>
116+
</object>
117+
<packing>
118+
<property name="expand">False</property>
119+
<property name="fill">True</property>
120+
<property name="padding">2</property>
121+
<property name="position">4</property>
122+
</packing>
123+
</child>
124+
</object>
125+
<packing>
126+
<property name="expand">False</property>
127+
<property name="fill">True</property>
128+
<property name="position">0</property>
129+
</packing>
130+
</child>
43131
<child>
44132
<object class="GtkBox" id="day-start box">
45133
<property name="visible">True</property>

src/hamster-cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
from hamster.lib import default_logger, stuff
4747
from hamster.lib import datetime as dt
4848
from hamster.lib.fact import Fact
49-
49+
from hamster.lib.notifsmanager import notifs_mgr
5050

5151
logger = default_logger(__file__)
5252

src/hamster/lib/configuration.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,5 +181,19 @@ def day_start(self):
181181
hours, minutes = divmod(day_start_minutes, 60)
182182
return dt.time(hours, minutes)
183183

184+
@property
185+
def notify_interval(self):
186+
"""Notifications every X minutes"""
187+
return self.get("notify-interval-minutes")
188+
189+
@property
190+
def notifications_enabled(self):
191+
"""Enable/Disable notifications"""
192+
return self.get("notifications-enabled")
193+
194+
@property
195+
def notify_on_idle(self) -> bool:
196+
"""Enable/Disable notifications when no activity is set"""
197+
return self.get("notify-on-idle-enabled")
184198

185199
conf = GSettingsStore()

src/hamster/lib/notifsmanager.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# - coding: utf-8 -
2+
3+
# Copyright (C) 2020 Sharaf Zaman <sharafzaz121@gmail.com>
4+
5+
# This file is part of Project Hamster.
6+
7+
# Project Hamster is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation, either version 3 of the License, or
10+
# (at your option) any later version.
11+
12+
# Project Hamster is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
17+
# You should have received a copy of the GNU General Public License
18+
# along with Project Hamster. If not, see <http://www.gnu.org/licenses/>.
19+
20+
import datetime
21+
import dbus
22+
import hamster.client
23+
24+
from gi.repository import Gtk
25+
from gi.repository import GObject as gobject
26+
from hamster.lib.configuration import conf
27+
28+
29+
class Notification(object):
30+
def __init__(self):
31+
self.bus = dbus.SessionBus()
32+
self.appname = "Hamster Time Tracker"
33+
self.replace_id = 0
34+
# FIXME: icon location?
35+
self.icon = "/usr/share/hamster-time-tracker/art/hamster-time-tracker.png"
36+
self.summary = "Hamster Time Tracker"
37+
self.hints = {}
38+
self.actions = []
39+
self.data = {}
40+
self.timeout = -1
41+
42+
def show(self, message):
43+
"""
44+
Show notitification
45+
returns: True if successful
46+
"""
47+
try:
48+
self.server = dbus.Interface(self.bus.get_object("org.freedesktop.Notifications",
49+
"/org/freedesktop/Notifications"),
50+
dbus_interface="org.freedesktop.Notifications")
51+
except dbus.exceptions.DBusException as e:
52+
# TODO: Log?
53+
print(e)
54+
print("Notifications will be disabled")
55+
return False
56+
57+
try:
58+
self.server.Notify(self.appname,
59+
self.replace_id,
60+
self.icon,
61+
self.summary,
62+
message,
63+
self.actions,
64+
self.hints,
65+
self.timeout
66+
)
67+
except:
68+
return False
69+
70+
return True
71+
72+
73+
class NotificationsManager(gobject.GObject):
74+
def __init__(self):
75+
self.notify_interval = conf.notify_interval
76+
self.minutes_passed = 0
77+
self.notification = Notification()
78+
gobject.timeout_add_seconds(60, self.check_interval)
79+
80+
def _notify_interval_value_changed(self, range):
81+
self.notify_interval = range.get_value()
82+
if self.notify_interval != conf.notify_interval:
83+
self.minutes_passed = 0
84+
conf.set("notify-interval-minutes", self.notify_interval)
85+
86+
def check_interval(self):
87+
if not conf.notifications_enabled:
88+
self.minutes_passed = 0
89+
return True
90+
91+
self.minutes_passed += 1
92+
93+
storage = hamster.client.Storage()
94+
facts = storage.get_todays_facts()
95+
96+
if self.minutes_passed == self.notify_interval:
97+
# if the activity is still active
98+
if len(facts) > 0 and facts[-1].end_time is None:
99+
timedelta_secs = (datetime.datetime.now() - facts[-1].start_time).seconds
100+
hours, rem = divmod(timedelta_secs, 60 * 60)
101+
minutes, seconds = divmod(rem, 60)
102+
if hours != 0:
103+
msg = str.format("Working on {} for {} hours and {} minutes", facts[-1].activity, hours, minutes)
104+
else:
105+
msg = str.format("Working on {} for {} minutes", facts[-1].activity, minutes)
106+
self.notification.show(msg)
107+
elif conf.notify_on_idle:
108+
self.notification.show("No Activity")
109+
110+
self.minutes_passed = 0
111+
112+
return True
113+
114+
def send_test(self):
115+
return self.notification.show("This is a test notification!")
116+
117+
118+
notifs_mgr = NotificationsManager()

src/hamster/preferences.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from hamster.lib import datetime as dt
2626
from hamster.lib import stuff
2727
from hamster.lib.configuration import Controller, runtime, conf
28+
from hamster.lib.notifsmanager import notifs_mgr
2829

2930

3031
def get_prev(selection, model):
@@ -133,11 +134,21 @@ def __init__(self):
133134
(selection, selection.connect('changed', self.category_changed_cb, self.category_store))
134135
])
135136

137+
# Tracking tab
136138
self.day_start = widgets.TimeInput(dt.time(5,30))
137139
self.get_widget("day_start_placeholder").add(self.day_start)
138140

141+
self.notify_scale = self.get_widget("notify-interval-scale")
142+
self.notify_scale.set_range(1, 120)
143+
144+
self.notifs_enabled_toggle = self.get_widget("notifs-enabled-toggle")
145+
self.notification_box = self.get_widget("notification-box")
146+
139147
self.load_config()
140148

149+
self.notify_scale.connect("value-changed", notifs_mgr._notify_interval_value_changed)
150+
self.notifs_enabled_toggle.connect("toggled", self._on_notifications_toggled)
151+
141152
# Allow enable drag and drop of rows including row move
142153
self.activity_tree.enable_model_drag_source(gdk.ModifierType.BUTTON1_MASK,
143154
self.TARGETS,
@@ -174,6 +185,14 @@ def load_config(self, *args):
174185
self.tags = [tag["name"] for tag in runtime.storage.get_tags(only_autocomplete=True)]
175186
self.get_widget("autocomplete_tags").set_text(", ".join(self.tags))
176187

188+
# enable/disable notification related settings
189+
self.notifs_enabled_toggle.set_active(conf.notifications_enabled)
190+
self.notification_box.set_sensitive(conf.notifications_enabled)
191+
192+
self.notify_scale.set_value(conf.notify_interval)
193+
self.get_widget("notify-on-idle").set_active(conf.notify_on_idle)
194+
195+
177196
def on_autocomplete_tags_view_focus_out_event(self, view, event):
178197
buf = self.get_widget("autocomplete_tags")
179198
updated_tags = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), 0)
@@ -509,3 +528,20 @@ def on_day_start_changed(self, widget):
509528
conf.set("day-start-minutes", day_start)
510529
def on_close_button_clicked(self, button):
511530
self.close_window()
531+
532+
def _on_notifications_toggled(self, checkbox):
533+
# TODO: Show error message next to the widget
534+
# Test only if activated
535+
if checkbox.get_active():
536+
if notifs_mgr.send_test():
537+
self.notification_box.set_sensitive(checkbox.get_active())
538+
conf.set("notifications-enabled", checkbox.get_active())
539+
else:
540+
checkbox.set_active(False)
541+
542+
self.notification_box.set_sensitive(checkbox.get_active())
543+
conf.set("notifications-enabled", checkbox.get_active())
544+
545+
def _notify_on_idle_toggled(self, checkbox):
546+
conf.set("notify-on-idle-enabled", checkbox.get_active())
547+

0 commit comments

Comments
 (0)