From 3766a6048d6faa9ec2a8cc5f066e3c1739773387 Mon Sep 17 00:00:00 2001 From: Miguel Jacq Date: Mon, 22 May 2017 16:47:12 +1000 Subject: [PATCH] Add desktop notification messages on download events (via systray) --- onionshare/settings.py | 1 + onionshare_gui/onionshare_gui.py | 18 ++++++++++++++++++ onionshare_gui/settings_dialog.py | 13 +++++++++++++ share/locale/en.json | 8 ++++++++ 4 files changed, 40 insertions(+) diff --git a/onionshare/settings.py b/onionshare/settings.py index 0eeb5da2..b5f873aa 100644 --- a/onionshare/settings.py +++ b/onionshare/settings.py @@ -46,6 +46,7 @@ class Settings(object): 'auth_type': 'no_auth', 'auth_password': '', 'close_after_first_download': True, + 'systray_notifications': True, 'use_stealth': False, 'use_autoupdate': True, 'autoupdate_timestamp': None diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py index 6eca4507..cb84d747 100644 --- a/onionshare_gui/onionshare_gui.py +++ b/onionshare_gui/onionshare_gui.py @@ -46,6 +46,8 @@ class OnionShareGui(QtWidgets.QMainWindow): def __init__(self, onion, qtapp, app, filenames): super(OnionShareGui, self).__init__() + self._initSystemTray() + common.log('OnionShareGui', '__init__') self.onion = onion @@ -144,6 +146,16 @@ class OnionShareGui(QtWidgets.QMainWindow): # After connecting to Tor, check for updates self.check_for_updates() + def _initSystemTray(self): + menu = QtWidgets.QMenu() + exitAction = menu.addAction(strings._('systray_menu_exit', True)) + exitAction.triggered.connect(sys.exit) + + self.systemTray = QtWidgets.QSystemTrayIcon(self) + self.systemTray.setIcon(QtGui.QIcon(common.get_resource_path('images/logo.png'))) + self.systemTray.setContextMenu(menu) + self.systemTray.show() + def _tor_connection_canceled(self): """ If the user cancels before Tor finishes connecting, ask if they want to @@ -361,6 +373,8 @@ class OnionShareGui(QtWidgets.QMainWindow): self.downloads_container.show() # show the downloads layout self.downloads.add_download(event["data"]["id"], web.zip_filesize) self.new_download = True + if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'): + self.systemTray.showMessage(strings._('systray_download_started_title', True), strings._('systray_download_started_message', True)) elif event["type"] == web.REQUEST_RATE_LIMIT: self.stop_server() @@ -371,12 +385,16 @@ class OnionShareGui(QtWidgets.QMainWindow): # is the download complete? if event["data"]["bytes"] == web.zip_filesize: + if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'): + self.systemTray.showMessage(strings._('systray_download_completed_title', True), strings._('systray_download_completed_message', True)) # close on finish? if not web.get_stay_open(): self.server_status.stop_server() elif event["type"] == web.REQUEST_CANCELED: self.downloads.cancel_download(event["data"]["id"]) + if self.systemTray.supportsMessages() and self.settings.get('systray_notifications'): + self.systemTray.showMessage(strings._('systray_download_canceled_title', True), strings._('systray_download_canceled_message', True)) elif event["path"] != '/favicon.ico': self.status_bar.showMessage('[#{0:d}] {1:s}: {2:s}'.format(web.error404_count, strings._('other_page_loaded', True), event["path"])) diff --git a/onionshare_gui/settings_dialog.py b/onionshare_gui/settings_dialog.py index 79a35101..c8df0f6c 100644 --- a/onionshare_gui/settings_dialog.py +++ b/onionshare_gui/settings_dialog.py @@ -52,9 +52,15 @@ class SettingsDialog(QtWidgets.QDialog): self.close_after_first_download_checkbox.setCheckState(QtCore.Qt.Checked) self.close_after_first_download_checkbox.setText(strings._("gui_settings_close_after_first_download_option", True)) + # Whether or not to show systray notifications + self.systray_notifications_checkbox = QtWidgets.QCheckBox() + self.systray_notifications_checkbox.setCheckState(QtCore.Qt.Checked) + self.systray_notifications_checkbox.setText(strings._("gui_settings_systray_notifications", True)) + # Sharing options layout sharing_group_layout = QtWidgets.QVBoxLayout() sharing_group_layout.addWidget(self.close_after_first_download_checkbox) + sharing_group_layout.addWidget(self.systray_notifications_checkbox) sharing_group = QtWidgets.QGroupBox(strings._("gui_settings_sharing_label", True)) sharing_group.setLayout(sharing_group_layout) @@ -257,6 +263,12 @@ class SettingsDialog(QtWidgets.QDialog): else: self.close_after_first_download_checkbox.setCheckState(QtCore.Qt.Unchecked) + systray_notifications = self.old_settings.get('systray_notifications') + if systray_notifications: + self.systray_notifications_checkbox.setCheckState(QtCore.Qt.Checked) + else: + self.systray_notifications_checkbox.setCheckState(QtCore.Qt.Unchecked) + use_stealth = self.old_settings.get('use_stealth') if use_stealth: self.stealth_checkbox.setCheckState(QtCore.Qt.Checked) @@ -499,6 +511,7 @@ class SettingsDialog(QtWidgets.QDialog): settings.load() # To get the last update timestamp settings.set('close_after_first_download', self.close_after_first_download_checkbox.isChecked()) + settings.set('systray_notifications', self.systray_notifications_checkbox.isChecked()) settings.set('use_stealth', self.stealth_checkbox.isChecked()) if self.connection_type_bundled_radio.isChecked(): diff --git a/share/locale/en.json b/share/locale/en.json index 701b067c..f521e32b 100644 --- a/share/locale/en.json +++ b/share/locale/en.json @@ -16,6 +16,13 @@ "large_filesize": "Warning: Sending large files could take hours", "error_tails_invalid_port": "Invalid value, port must be an integer", "error_tails_unknown_root": "Unknown error with Tails root process", + "systray_menu_exit": "Quit", + "systray_download_started_title": "Download started", + "systray_download_started_message": "A user has begun to download your share", + "systray_download_completed_title": "Download complete", + "systray_download_completed_message": "The user completed downloading your share", + "systray_download_canceled_title": "Download canceled", + "systray_download_canceled_message": "The user has canceled the download", "help_local_only": "Do not attempt to use tor: for development only", "help_stay_open": "Keep onion service running after download has finished", "help_transparent_torification": "My system is transparently torified", @@ -64,6 +71,7 @@ "gui_settings_autoupdate_check_button": "Check For Updates", "gui_settings_sharing_label": "Sharing options", "gui_settings_close_after_first_download_option": "Stop sharing after first download", + "gui_settings_systray_notifications": "Show notifications when a download commences or completes", "gui_settings_connection_type_label": "How should OnionShare connect to Tor?", "gui_settings_connection_type_bundled_option": "Use Tor that is bundled with OnionShare", "gui_settings_connection_type_automatic_option": "Attempt automatic configuration with Tor Browser",