Skip to content

Commit a57de00

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 780d675 commit a57de00

6 files changed

Lines changed: 284 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: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
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 logging
21+
logger = logging.getLogger(__name__) # noqa: E402
22+
import datetime
23+
import dbus
24+
import hamster.client
25+
26+
from gi.repository import Gtk
27+
from gi.repository import GObject as gobject
28+
from hamster.lib.configuration import conf
29+
30+
31+
class Notification(object):
32+
def __init__(self):
33+
self.bus = dbus.SessionBus()
34+
self.appname = "Hamster Time Tracker"
35+
self.replace_id = 0
36+
self.summary = "Hamster Time Tracker"
37+
self.hints = {}
38+
self.actions = []
39+
self.data = {}
40+
self.timeout = -1
41+
42+
info = Gtk.IconTheme().lookup_icon("hamster-time-tracker", 0, 0)
43+
self.icon = info.get_filename()
44+
45+
def show(self, message):
46+
"""
47+
Show notitification
48+
returns: True if successful
49+
"""
50+
try:
51+
self.server = dbus.Interface(self.bus.get_object("org.freedesktop.Notifications",
52+
"/org/freedesktop/Notifications"),
53+
dbus_interface="org.freedesktop.Notifications")
54+
except dbus.exceptions.DBusException as e:
55+
# TODO: Log?
56+
logger.error(e)
57+
logger.warning("Notifications will be disabled")
58+
return False
59+
60+
try:
61+
self.notif_id = self.server.Notify(
62+
self.appname,
63+
self.replace_id,
64+
self.icon,
65+
self.summary,
66+
message,
67+
self.actions,
68+
self.hints,
69+
self.timeout)
70+
except:
71+
return False
72+
73+
return True
74+
75+
def close(self):
76+
try: self.server.CloseNotification(self.notif_id)
77+
except: pass
78+
79+
80+
81+
class NotificationsManager(gobject.GObject):
82+
def __init__(self):
83+
self.notify_interval = conf.notify_interval
84+
self.minutes_passed = 0
85+
self.notification = Notification()
86+
gobject.timeout_add_seconds(60, self.check_interval)
87+
88+
def notify_interval_changed(self, value):
89+
self.minutes_passed = 0
90+
self.notify_interval = value
91+
92+
def check_interval(self):
93+
if not conf.notifications_enabled:
94+
self.minutes_passed = 0
95+
return True
96+
97+
self.minutes_passed += 1
98+
99+
storage = hamster.client.Storage()
100+
facts = storage.get_todays_facts()
101+
102+
if self.minutes_passed == self.notify_interval:
103+
# if the activity is still active
104+
if len(facts) > 0 and facts[-1].end_time is None:
105+
timedelta_secs = (datetime.datetime.now() - facts[-1].start_time).seconds
106+
hours, rem = divmod(timedelta_secs, 60 * 60)
107+
minutes, seconds = divmod(rem, 60)
108+
if hours != 0:
109+
msg = str.format("Working on {} for {} hours and {} minutes", facts[-1].activity, hours, minutes)
110+
else:
111+
msg = str.format("Working on {} for {} minutes", facts[-1].activity, minutes)
112+
self.notification.show(msg)
113+
elif conf.notify_on_idle:
114+
self.notification.show("No Activity")
115+
116+
self.notification.close()
117+
118+
self.minutes_passed = 0
119+
120+
return True
121+
122+
def send_test(self):
123+
return self.notification.show("This is a test notification!")
124+
125+
126+
notifs_mgr = NotificationsManager()

src/hamster/preferences.py

Lines changed: 40 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", self._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,24 @@ 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+
548+
def _notify_interval_value_changed(self, range):
549+
notify_interval = range.get_value()
550+
conf.set("notify-interval-minutes", notify_interval)
551+
notifs_mgr.notify_interval_changed(notify_interval)

0 commit comments

Comments
 (0)