Merge lp:~alecu/ubuntuone-client/config-notifications-2 into lp:ubuntuone-client
- config-notifications-2
- Merge into trunk
Status: | Merged | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | dobey | ||||||||||||||||
Approved revision: | 870 | ||||||||||||||||
Merged at revision: | 870 | ||||||||||||||||
Proposed branch: | lp:~alecu/ubuntuone-client/config-notifications-2 | ||||||||||||||||
Merge into: | lp:ubuntuone-client | ||||||||||||||||
Diff against target: |
524 lines (+286/-35) 2 files modified
tests/status/test_aggregator.py (+226/-19) ubuntuone/status/aggregator.py (+60/-16) |
||||||||||||||||
To merge this branch: | bzr merge lp:~alecu/ubuntuone-client/config-notifications-2 | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Eric Casteleijn (community) | Approve | ||
Martin Albisetti (community) | Approve | ||
Review via email:
|
Commit message
disable notifications according to config, don't show partial count of files done (LP:#717172, LP:#715842, LP:#715887)
Description of the change
disable notifications according to config, don't show partial count of files done (LP:#717172, LP:#715842, LP:#715887)
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Martin Albisetti (beuno) : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu One Auto Pilot (otto-pilot) wrote : | # |
The attempt to merge lp:~alecu/ubuntuone-client/config-notifications-2 into lp:ubuntuone-client failed. Below is the output from the failed tests.
/usr/bin/
checking for autoconf >= 2.53...
testing autoconf2.50... not found.
testing autoconf... found 2.67
checking for automake >= 1.10...
testing automake-1.11... found 1.11.1
checking for libtool >= 1.5...
testing libtoolize... found 2.2.6b
checking for intltool >= 0.30...
testing intltoolize... found 0.41.1
checking for pkg-config >= 0.14.0...
testing pkg-config... found 0.25
checking for gtk-doc >= 1.0...
testing gtkdocize... found 1.16
Checking for required M4 macros...
Checking for forbidden M4 macros...
Processing ./configure.ac
Running libtoolize...
libtoolize: putting auxiliary files in `.'.
libtoolize: copying file `./ltmain.sh'
libtoolize: putting macros in AC_CONFIG_
libtoolize: copying file `m4/libtool.m4'
libtoolize: copying file `m4/ltoptions.m4'
libtoolize: copying file `m4/ltsugar.m4'
libtoolize: copying file `m4/ltversion.m4'
libtoolize: copying file `m4/lt~obsolete.m4'
Running intltoolize...
Running gtkdocize...
Running aclocal-1.11...
Running autoconf...
Running autoheader...
Running automake-1.11...
Running ./configure --enable-gtk-doc --enable-debug ...
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for style of include used by make... GNU
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking dependency style of gcc... gcc3
checking for library containing strerror... none required
checking for gcc... (cached) gcc
checking whether we are using the GNU C compiler... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to accept ISO C89... (cached) none needed
checking dependency style of gcc... (cached) gcc3
checking build system type... i686-pc-linux-gnu
checking host system type... i686-pc-linux-gnu
checking for a sed that does not truncate output... /bin/sed
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for fgrep... /bin/grep -F
checking for ld used by gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 1572864
checking whether the shell understands some XSI constructs... yes
checking whether the shell understands "+="... yes
checking for /usr/bin/ld option to reload object files... -r
checking for objdump... objdump
checking how to recognize dependent...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu One Auto Pilot (otto-pilot) wrote : | # |
There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.
Preview Diff
1 | === modified file 'tests/status/test_aggregator.py' |
2 | --- tests/status/test_aggregator.py 2011-02-11 22:01:23 +0000 |
3 | +++ tests/status/test_aggregator.py 2011-02-16 19:09:08 +0000 |
4 | @@ -132,18 +132,27 @@ |
5 | def __init__(self, application_name="fake app"): |
6 | """Initialize this instance.""" |
7 | self.notifications_shown = [] |
8 | + self.notification_switch = None |
9 | self.application_name = application_name |
10 | |
11 | def send_notification(self, title, message, icon=None, append=False): |
12 | """Show a notification to the user.""" |
13 | + if (self.notification_switch is not None |
14 | + and not self.notification_switch.enabled): |
15 | + return |
16 | self.notifications_shown.append((title, message, icon, append)) |
17 | return len(self.notifications_shown) - 1 |
18 | |
19 | - def update_notification(self, notification, new_title, new_message, |
20 | + def update_notification(self, notification_id, new_title, new_message, |
21 | new_icon=None): |
22 | """Update the notification with a new message body.""" |
23 | + if (self.notification_switch is not None |
24 | + and not self.notification_switch.enabled): |
25 | + return |
26 | + if notification_id is None: |
27 | + return |
28 | title, old_message, icon, append = self.notifications_shown[ |
29 | - notification] |
30 | + notification_id] |
31 | if new_icon is not None: |
32 | icon = new_icon |
33 | # we store it as a new notification, to ease testing |
34 | @@ -155,8 +164,9 @@ |
35 | """Builds a notification singleton, that logs all notifications shown.""" |
36 | instance = FakeNotification() |
37 | |
38 | - def get_instance(): |
39 | + def get_instance(notification_switch): |
40 | """Returns the single instance.""" |
41 | + instance.notification_switch = notification_switch |
42 | return instance |
43 | |
44 | return get_instance |
45 | @@ -192,6 +202,7 @@ |
46 | self.discovered = 0 |
47 | self.completed = 0 |
48 | self.restart_progress_bubble_called = False |
49 | + self.notification_switch = aggregator.NotificationSwitch() |
50 | |
51 | def get_discovery_message(self): |
52 | """Return the file discovery message.""" |
53 | @@ -220,13 +231,122 @@ |
54 | """Reset the progress bubble.""" |
55 | self.restart_progress_bubble_called = True |
56 | |
57 | + def build_notification(self): |
58 | + """Create a new toggleable notification object.""" |
59 | + return self.notification_switch.build_notification() |
60 | + |
61 | + |
62 | +class ToggleableNotificationTestCase(TestCase): |
63 | + """Test the ToggleableNotification class.""" |
64 | + |
65 | + def setUp(self): |
66 | + """Initialize this test instance.""" |
67 | + self.patch(aggregator, "Notification", FakeNotification) |
68 | + self.notification_switch = aggregator.NotificationSwitch() |
69 | + self.toggleable = self.notification_switch.build_notification() |
70 | + |
71 | + def assertShown(self, notification): |
72 | + """Assert that the notification was shown.""" |
73 | + self.assertIn(notification, |
74 | + self.toggleable.notification.notifications_shown) |
75 | + |
76 | + def assertNotShown(self, notification): |
77 | + """Assert that the notification was shown.""" |
78 | + self.assertNotIn(notification, |
79 | + self.toggleable.notification.notifications_shown) |
80 | + |
81 | + def test_send_notification_passes_thru(self): |
82 | + """The send_notification method passes thru.""" |
83 | + args = (1, 2, 3, 4) |
84 | + self.toggleable.send_notification(*args) |
85 | + self.assertShown(args) |
86 | + |
87 | + def test_update_notification_passes_thru(self): |
88 | + """The update_notification method passes thru.""" |
89 | + show_args = ("title", "body", "icon", "append") |
90 | + update_args = ("other title", "other body") |
91 | + expected = update_args + show_args[2:] |
92 | + notification_id = self.toggleable.send_notification(*show_args) |
93 | + self.toggleable.update_notification(notification_id, *update_args) |
94 | + self.assertShown(expected) |
95 | + |
96 | + def test_send_notification_honored_when_enabled(self): |
97 | + """The send_notification method is honored when enabled.""" |
98 | + self.notification_switch.enable_notifications() |
99 | + args = (aggregator.UBUNTUONE_TITLE, "hello", None, False) |
100 | + self.toggleable.send_notification(*args) |
101 | + self.assertShown(args) |
102 | + |
103 | + def test_send_notification_ignored_when_disabled(self): |
104 | + """The send_notification method is ignored when disabled.""" |
105 | + self.notification_switch.disable_notifications() |
106 | + args = (aggregator.UBUNTUONE_TITLE, "hello", None, False) |
107 | + self.toggleable.send_notification(*args) |
108 | + self.assertNotShown(args) |
109 | + |
110 | + def test_update_notification_honored_when_enabled(self): |
111 | + """The update_notification method is honored when enabled.""" |
112 | + self.notification_switch.enable_notifications() |
113 | + show_args = ("title", "body", "icon", "append") |
114 | + update_args = ("other title", "other body") |
115 | + expected = update_args + show_args[2:] |
116 | + notification_id = self.toggleable.send_notification(*show_args) |
117 | + self.toggleable.update_notification(notification_id, *update_args) |
118 | + self.assertShown(expected) |
119 | + |
120 | + def test_update_notification_ignored_when_disabled(self): |
121 | + """The update_notification method is ignored when disabled.""" |
122 | + self.notification_switch.disable_notifications() |
123 | + show_args = ("title", "body", "icon", "append") |
124 | + update_args = ("other title", "other body") |
125 | + expected = update_args + show_args[2:] |
126 | + notification_id = self.toggleable.send_notification(*show_args) |
127 | + self.toggleable.update_notification(notification_id, *update_args) |
128 | + self.assertNotShown(expected) |
129 | + |
130 | + def test_update_after_disabled_show(self): |
131 | + """An update is ignored if the corresponding show was disabled.""" |
132 | + self.notification_switch.disable_notifications() |
133 | + show_args = ("title", "body", "icon", "append") |
134 | + update_args = ("other title", "other body") |
135 | + expected = update_args + show_args[2:] |
136 | + notification_id = self.toggleable.send_notification(*show_args) |
137 | + self.notification_switch.enable_notifications() |
138 | + self.toggleable.update_notification(notification_id, *update_args) |
139 | + self.assertNotShown(expected) |
140 | + |
141 | + |
142 | +class NotificationSwitchTestCase(TestCase): |
143 | + """Test the NotificationSwitch class.""" |
144 | + |
145 | + def setUp(self): |
146 | + """Initialize this test instance.""" |
147 | + self.notification_switch = aggregator.NotificationSwitch() |
148 | + |
149 | + def test_build_notification(self): |
150 | + """A new notification instance is returned.""" |
151 | + notification = self.notification_switch.build_notification() |
152 | + self.assertEqual(notification.notification_switch, |
153 | + self.notification_switch) |
154 | + |
155 | + def test_enable_notifications(self): |
156 | + """The switch is turned on.""" |
157 | + self.notification_switch.enable_notifications() |
158 | + self.assertTrue(self.notification_switch.enabled) |
159 | + |
160 | + def test_disable_notifications(self): |
161 | + """The switch is turned off.""" |
162 | + self.notification_switch.disable_notifications() |
163 | + self.assertFalse(self.notification_switch.enabled) |
164 | + |
165 | |
166 | class FileDiscoveryBubbleTestCase(TestCase): |
167 | """Test the FileDiscoveryBubble class.""" |
168 | |
169 | def setUp(self): |
170 | """Initialize this test instance.""" |
171 | - self.patch(aggregator, "Notification", FakeNotificationSingleton()) |
172 | + self.patch(aggregator, "ToggleableNotification", |
173 | + FakeNotificationSingleton()) |
174 | self.clock = PatchedClock() |
175 | self.aggregator = FakeStatusAggregator(clock=self.clock) |
176 | self.bubble = aggregator.FileDiscoveryBubble(self.aggregator, |
177 | @@ -384,7 +504,8 @@ |
178 | |
179 | def setUp(self): |
180 | """Initialize this test instance.""" |
181 | - self.patch(aggregator, "Notification", FakeNotificationSingleton()) |
182 | + self.patch(aggregator, "ToggleableNotification", |
183 | + FakeNotificationSingleton()) |
184 | self.clock = PatchedClock() |
185 | self.aggregator = FakeStatusAggregator(clock=self.clock) |
186 | self.bubble = aggregator.ProgressBubble(self.aggregator, |
187 | @@ -468,7 +589,8 @@ |
188 | |
189 | def setUp(self): |
190 | """Initialize this test instance.""" |
191 | - self.patch(aggregator, "Notification", FakeNotificationSingleton()) |
192 | + self.patch(aggregator, "ToggleableNotification", |
193 | + FakeNotificationSingleton()) |
194 | self.clock = PatchedClock() |
195 | self.aggregator = FakeStatusAggregator(clock=self.clock) |
196 | self.bubble = aggregator.FinalStatusBubble(self.aggregator) |
197 | @@ -611,6 +733,7 @@ |
198 | def __init__(self, clock): |
199 | """Initialize this fake instance.""" |
200 | self.queued_commands = set() |
201 | + self.notification_switch = aggregator.NotificationSwitch() |
202 | |
203 | def queue_done(self): |
204 | """The queue completed all operations.""" |
205 | @@ -624,6 +747,10 @@ |
206 | """A new command was unqueued.""" |
207 | self.queued_commands.discard(command) |
208 | |
209 | + def build_notification(self): |
210 | + """Create a new toggleable notification object.""" |
211 | + return self.notification_switch.build_notification() |
212 | + |
213 | download_started = misc_command_queued |
214 | download_finished = misc_command_unqueued |
215 | upload_started = misc_command_queued |
216 | @@ -637,7 +764,8 @@ |
217 | """Initialize this test instance.""" |
218 | BaseTwistedTestCase.setUp(self) |
219 | self.patch(aggregator, "StatusAggregator", FakeAggregator) |
220 | - self.patch(aggregator, "Notification", FakeNotificationSingleton()) |
221 | + self.patch(aggregator, "ToggleableNotification", |
222 | + FakeNotificationSingleton()) |
223 | self.patch(aggregator, "Messaging", FakeMessaging) |
224 | self.fakefsm = None |
225 | self.fakevm = FakeVolumeManager() |
226 | @@ -827,6 +955,12 @@ |
227 | aggregator.ConnectionMadeStatus.MESSAGE_ONE, None, False), |
228 | self.status_frontend.notification.notifications_shown[0]) |
229 | |
230 | + def test_set_show_all_notifications(self): |
231 | + """Test the set_show_all_notifications method.""" |
232 | + self.status_frontend.set_show_all_notifications(False) |
233 | + self.assertFalse(self.status_frontend.aggregator. |
234 | + notification_switch.enabled) |
235 | + |
236 | |
237 | class StatusEventTestCase(TestCase): |
238 | """Test the status event class and children.""" |
239 | @@ -1119,8 +1253,8 @@ |
240 | self.aggregator.download_total = 8 |
241 | self.aggregator.done_counter = 9 |
242 | self.aggregator.total_counter = 20 |
243 | - expected = (aggregator.PROGRESS_UPLOADED % (5, 10) + " " + |
244 | - aggregator.PROGRESS_DOWNLOADED % (3, 8) + " " + |
245 | + expected = (aggregator.FILES_UPLOADING % 10 + " " + |
246 | + aggregator.FILES_DOWNLOADING % 8 + " " + |
247 | aggregator.PROGRESS_COMPLETED % int(100.0 * 9 / 20)) |
248 | result = self.aggregator.get_progress_message() |
249 | self.assertEqual(expected, result) |
250 | @@ -1133,7 +1267,7 @@ |
251 | self.aggregator.download_total = 8 |
252 | self.aggregator.done_counter = 9 |
253 | self.aggregator.total_counter = 20 |
254 | - expected = (aggregator.PROGRESS_DOWNLOADED % (3, 8) + " " + |
255 | + expected = (aggregator.FILES_DOWNLOADING % 8 + " " + |
256 | aggregator.PROGRESS_COMPLETED % int(100.0 * 9 / 20)) |
257 | result = self.aggregator.get_progress_message() |
258 | self.assertEqual(expected, result) |
259 | @@ -1146,7 +1280,7 @@ |
260 | self.aggregator.download_total = 0 |
261 | self.aggregator.done_counter = 9 |
262 | self.aggregator.total_counter = 20 |
263 | - expected = (aggregator.PROGRESS_UPLOADED % (5, 10) + " " + |
264 | + expected = (aggregator.FILES_UPLOADING % 10 + " " + |
265 | aggregator.PROGRESS_COMPLETED % int(100.0 * 9 / 20)) |
266 | result = self.aggregator.get_progress_message() |
267 | self.assertEqual(expected, result) |
268 | @@ -1189,13 +1323,37 @@ |
269 | self.aggregator.restart_progress_bubble() |
270 | self.assertTrue(self.aggregator.progress_bubble.started) |
271 | |
272 | - def test_queue_done(self): |
273 | - """On queue done, show final bubble and reset counters.""" |
274 | - fc = FakeCommand() |
275 | - self.status_frontend.upload_started(fc) |
276 | - old_final_bubble = self.aggregator.final_status_bubble |
277 | - self.aggregator.queue_done() |
278 | - self.assertTrue(old_final_bubble.shown) |
279 | + def test_queue_done_shows_bubble_when_downloads_happened(self): |
280 | + """On queue done, show final bubble if downloads happened.""" |
281 | + fc = FakeCommand() |
282 | + self.status_frontend.download_started(fc) |
283 | + self.status_frontend.download_finished(fc) |
284 | + old_final_bubble = self.aggregator.final_status_bubble |
285 | + self.aggregator.queue_done() |
286 | + self.assertTrue(old_final_bubble.shown) |
287 | + |
288 | + def test_queue_done_shows_bubble_when_uploads_happened(self): |
289 | + """On queue done, show final bubble if uploads happened.""" |
290 | + fc = FakeCommand() |
291 | + self.status_frontend.upload_started(fc) |
292 | + self.status_frontend.upload_finished(fc) |
293 | + old_final_bubble = self.aggregator.final_status_bubble |
294 | + self.aggregator.queue_done() |
295 | + self.assertTrue(old_final_bubble.shown) |
296 | + |
297 | + def test_queue_done_does_not_show_bubble_when_no_transfers_happened(self): |
298 | + """On queue done, don't show final bubble if no transfers happened.""" |
299 | + fc = FakeCommand() |
300 | + self.status_frontend.upload_started(fc) |
301 | + old_final_bubble = self.aggregator.final_status_bubble |
302 | + self.aggregator.queue_done() |
303 | + self.assertFalse(old_final_bubble.shown) |
304 | + |
305 | + def test_queue_done_resets_status_and_hides_progressbar(self): |
306 | + """On queue done, reset counters and hide progressbar.""" |
307 | + fc = FakeCommand() |
308 | + self.status_frontend.upload_started(fc) |
309 | + self.aggregator.queue_done() |
310 | self.assertStatusReset() |
311 | self.assertEqual(0.0, self.aggregator.progress_bar.percentage) |
312 | self.assertFalse(self.aggregator.progress_bar.visible) |
313 | @@ -1229,10 +1387,13 @@ |
314 | |
315 | def test_all_together_now(self): |
316 | """Make all parts work together.""" |
317 | - self.patch(aggregator, "Notification", FakeNotificationSingleton()) |
318 | + self.patch(aggregator, "ToggleableNotification", |
319 | + FakeNotificationSingleton()) |
320 | clock = PatchedClock() |
321 | upload = FakeCommand() |
322 | sf = aggregator.StatusFrontend(clock=clock) |
323 | + sf.set_show_all_notifications(True) |
324 | + |
325 | clock.advance(aggregator.ProgressBubble.sleep_delay) |
326 | # the progress bar is not visible yet |
327 | self.assertFalse(sf.aggregator.progress_bar.visible) |
328 | @@ -1276,3 +1437,49 @@ |
329 | clock.advance(aggregator.ProgressBubble.sleep_delay * 2) |
330 | # no more notifications are shown |
331 | self.assertEqual(5, len(notifications_shown)) |
332 | + |
333 | + def test_all_together_now_off(self): |
334 | + """Make all parts work together, but with notifications off.""" |
335 | + self.patch(aggregator, "ToggleableNotification", |
336 | + FakeNotificationSingleton()) |
337 | + clock = PatchedClock() |
338 | + upload = FakeCommand() |
339 | + sf = aggregator.StatusFrontend(clock=clock) |
340 | + sf.set_show_all_notifications(False) |
341 | + |
342 | + clock.advance(aggregator.ProgressBubble.sleep_delay) |
343 | + # the progress bar is not visible yet |
344 | + self.assertFalse(sf.aggregator.progress_bar.visible) |
345 | + sf.upload_started(upload) |
346 | + # the progress bar is now shown |
347 | + self.assertTrue(sf.aggregator.progress_bar.visible) |
348 | + notifications_shown = (sf.aggregator.file_discovery_bubble. |
349 | + notification.notifications_shown) |
350 | + # no notifications shown, never |
351 | + self.assertEqual(0, len(notifications_shown)) |
352 | + clock.advance(aggregator.FileDiscoveryGatheringState.initial_delay) |
353 | + self.assertEqual(0, len(notifications_shown)) |
354 | + download = FakeCommand() |
355 | + sf.download_started(download) |
356 | + self.assertEqual(0, len(notifications_shown)) |
357 | + # the progress still is zero |
358 | + self.assertEqual(0.0, sf.aggregator.progress_bar.percentage) |
359 | + clock.advance(aggregator.FileDiscoveryUpdateState.updates_delay) |
360 | + self.assertEqual(0, len(notifications_shown)) |
361 | + clock.advance(aggregator.FileDiscoveryUpdateState.updates_timeout - |
362 | + aggregator.FileDiscoveryUpdateState.updates_delay) |
363 | + sf.upload_finished(upload) |
364 | + # the progress bubble has no notifications yet |
365 | + self.assertEqual(None, sf.aggregator.progress_bubble.notification) |
366 | + clock.advance(aggregator.ProgressBubble.sleep_delay) |
367 | + self.assertEqual(0, len(notifications_shown)) |
368 | + sf.upload_finished(download) |
369 | + # the progress still is now 100% |
370 | + self.assertEqual(100.0, sf.aggregator.progress_bar.percentage) |
371 | + self.assertEqual(0, len(notifications_shown)) |
372 | + clock.advance(aggregator.ProgressBubble.sleep_delay) |
373 | + self.assertEqual(0, len(notifications_shown)) |
374 | + sf.queue_done() |
375 | + self.assertEqual(0, len(notifications_shown)) |
376 | + clock.advance(aggregator.ProgressBubble.sleep_delay * 2) |
377 | + self.assertEqual(0, len(notifications_shown)) |
378 | |
379 | === modified file 'ubuntuone/status/aggregator.py' |
380 | --- ubuntuone/status/aggregator.py 2011-02-14 19:16:19 +0000 |
381 | +++ ubuntuone/status/aggregator.py 2011-02-16 19:09:08 +0000 |
382 | @@ -39,16 +39,52 @@ |
383 | logger.addHandler(debug_handler) |
384 | |
385 | UBUNTUONE_TITLE = "Ubuntu One" |
386 | -NEW_UDFS_SENDER = "New Cloud Folder(s) Available" |
387 | +NEW_UDFS_SENDER = "New cloud folder(s) available" |
388 | FINAL_COMPLETED = "File synchronization completed." |
389 | -FINAL_UPLOADED = "%d files were uploaded to your cloud." |
390 | -FINAL_DOWNLOADED = "%d files were downloaded to your computer." |
391 | -FILES_UPLOADING = "%d files are uploading to your cloud." |
392 | -FILES_DOWNLOADING = "%d files are downloading to your computer." |
393 | -PROGRESS_UPLOADED = "Uploaded %d/%d files." |
394 | -PROGRESS_DOWNLOADED = "Downloaded %d/%d files." |
395 | +FINAL_UPLOADED = "%d file(s) were uploaded to your personal cloud." |
396 | +FINAL_DOWNLOADED = "%d file(s) were downloaded to your computer." |
397 | +FILES_UPLOADING = "%d file(s) are uploading to your personal cloud." |
398 | +FILES_DOWNLOADING = "%d file(s) are downloading to your computer." |
399 | +PROGRESS_UPLOADED = "Uploaded %d/%d file(s)." |
400 | PROGRESS_COMPLETED = "%d%% completed." |
401 | |
402 | +class ToggleableNotification(object): |
403 | + """A controller for notifications that can be turned off.""" |
404 | + |
405 | + def __init__(self, notification_switch): |
406 | + """Initialize this instance.""" |
407 | + self.notification_switch = notification_switch |
408 | + self.notification = Notification() |
409 | + |
410 | + def send_notification(self, *args): |
411 | + """Passthru the notification.""" |
412 | + if self.notification_switch.enabled: |
413 | + return self.notification.send_notification(*args) |
414 | + |
415 | + def update_notification(self, notification_id, *args): |
416 | + """Passthru the update.""" |
417 | + if notification_id is not None and self.notification_switch.enabled: |
418 | + return self.notification.update_notification(notification_id, |
419 | + *args) |
420 | + |
421 | + |
422 | +class NotificationSwitch(object): |
423 | + """A switch that turns notifications on and off.""" |
424 | + |
425 | + enabled = True |
426 | + |
427 | + def build_notification(self): |
428 | + """Return a new notification instance.""" |
429 | + return ToggleableNotification(self) |
430 | + |
431 | + def enable_notifications(self): |
432 | + """Turn the switch on.""" |
433 | + self.enabled = True |
434 | + |
435 | + def disable_notifications(self): |
436 | + """Turn the switch off.""" |
437 | + self.enabled = False |
438 | + |
439 | |
440 | class StatusEvent(object): |
441 | """An event representing a status change.""" |
442 | @@ -328,7 +364,7 @@ |
443 | |
444 | def _start(self): |
445 | """The first file was found, so start gathering.""" |
446 | - self.notification = Notification() |
447 | + self.notification = self.status_aggregator.build_notification() |
448 | self._change_state(FileDiscoveryGatheringState) |
449 | |
450 | def _popup(self): |
451 | @@ -381,7 +417,7 @@ |
452 | |
453 | def _timeout(self, result): |
454 | """Show the bubble.""" |
455 | - self.notification = Notification() |
456 | + self.notification = self.status_aggregator.build_notification() |
457 | text = self.status_aggregator.get_progress_message() |
458 | self.notification.send_notification(UBUNTUONE_TITLE, text) |
459 | self.restart() |
460 | @@ -453,7 +489,7 @@ |
461 | |
462 | def show(self): |
463 | """Show the final status notification.""" |
464 | - self.notification = Notification() |
465 | + self.notification = self.status_aggregator.build_notification() |
466 | text = self.status_aggregator.get_final_status_message() |
467 | self.notification.send_notification(UBUNTUONE_TITLE, text) |
468 | |
469 | @@ -475,9 +511,14 @@ |
470 | def __init__(self, clock=reactor): |
471 | """Initialize this instance.""" |
472 | self.clock = clock |
473 | + self.notification_switch = NotificationSwitch() |
474 | self.reset() |
475 | self.progress_bar = ProgressBar(clock=self.clock) |
476 | |
477 | + def build_notification(self): |
478 | + """Create a new toggleable notification object.""" |
479 | + return self.notification_switch.build_notification() |
480 | + |
481 | def reset(self): |
482 | """Reset all counters and notifications.""" |
483 | self.total_counter = 0 |
484 | @@ -521,11 +562,9 @@ |
485 | assert self.total_counter > 0 |
486 | parts = [] |
487 | if self.upload_total: |
488 | - parts.append(PROGRESS_UPLOADED % (self.upload_done, |
489 | - self.upload_total)) |
490 | + parts.append(FILES_UPLOADING % self.upload_total) |
491 | if self.download_total: |
492 | - parts.append(PROGRESS_DOWNLOADED % (self.download_done, |
493 | - self.download_total)) |
494 | + parts.append(FILES_DOWNLOADING % self.download_total) |
495 | progress_percentage = 100.0 * self.done_counter / self.total_counter |
496 | parts.append(PROGRESS_COMPLETED % int(progress_percentage)) |
497 | return " ".join(parts) |
498 | @@ -546,7 +585,8 @@ |
499 | |
500 | def queue_done(self): |
501 | """Show final bubble and reset counters.""" |
502 | - self.final_status_bubble.show() |
503 | + if self.upload_done + self.download_done > 0: |
504 | + self.final_status_bubble.show() |
505 | self.progress_bar.completed() |
506 | self.reset() |
507 | |
508 | @@ -603,7 +643,7 @@ |
509 | def __init__(self, clock=reactor): |
510 | """Initialize this instance.""" |
511 | self.aggregator = StatusAggregator(clock=clock) |
512 | - self.notification = Notification() |
513 | + self.notification = self.aggregator.build_notification() |
514 | self.messaging = Messaging() |
515 | self.udf_message = None |
516 | |
517 | @@ -681,3 +721,7 @@ |
518 | |
519 | def set_show_all_notifications(self, value): |
520 | """Set the flag to show all notifications.""" |
521 | + if value: |
522 | + self.aggregator.notification_switch.enable_notifications() |
523 | + else: |
524 | + self.aggregator.notification_switch.disable_notifications() |
Great branch! +1