Skip to content

Commit

Permalink
Display systray notification to make offline mode more obvious to the…
Browse files Browse the repository at this point in the history
… users (PR #1342)

Display systray notification on backend disconnected event
  • Loading branch information
AntoineDupre authored Aug 5, 2020
2 parents bfed784 + f07a0e8 commit 5aca1b8
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 8 deletions.
1 change: 1 addition & 0 deletions newsfragments/1330.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Display systray notification to make offline mode more obvious to the users
15 changes: 14 additions & 1 deletion parsec/core/gui/central_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ class CentralWidget(QWidget, Ui_CentralWidget):
logout_requested = pyqtSignal()
new_notification = pyqtSignal(str, str)

def __init__(self, core, jobs_ctx, event_bus, **kwargs):
def __init__(self, core, jobs_ctx, event_bus, systray_notification, **kwargs):
super().__init__(**kwargs)
self.setupUi(self)

self.jobs_ctx = jobs_ctx
self.core = core
self.event_bus = event_bus
self.systray_notification = systray_notification

self.menu = MenuWidget(parent=self)
self.widget_menu.layout().addWidget(self.menu)
Expand Down Expand Up @@ -162,6 +163,7 @@ def _on_connection_state_changed(self, status, status_exc):
icon = None
tooltip = None
notif = None
disconnected = None

if status in (BackendConnStatus.READY, BackendConnStatus.INITIALIZING):
tooltip = text = _("TEXT_BACKEND_STATE_CONNECTED")
Expand All @@ -170,8 +172,10 @@ def _on_connection_state_changed(self, status, status_exc):
elif status == BackendConnStatus.LOST:
tooltip = text = _("TEXT_BACKEND_STATE_DISCONNECTED")
icon = QPixmap(":/icons/images/material/cloud_off.svg")
disconnected = True

elif status == BackendConnStatus.REFUSED:
disconnected = True
cause = status_exc.__cause__
if isinstance(cause, HandshakeAPIVersionError):
tooltip = _("TEXT_BACKEND_STATE_API_MISMATCH_versions").format(
Expand All @@ -194,10 +198,19 @@ def _on_connection_state_changed(self, status, status_exc):
tooltip = _("TEXT_BACKEND_STATE_CRASHED_cause").format(cause=str(status_exc.__cause__))
icon = QPixmap(":/icons/images/material/cloud_off.svg")
notif = ("ERROR", tooltip)
disconnected = True

self.menu.set_connection_state(text, tooltip, icon)
if notif:
self.new_notification.emit(*notif)
if disconnected:
self.systray_notification.emit(
"Parsec",
_("TEXT_SYSTRAY_BACKEND_DISCONNECT_organization").format(
organization=self.core.device.organization_id
),
5000,
)

def on_new_notification(self, notif_type, msg):
if notif_type == "REVOKED":
Expand Down
9 changes: 7 additions & 2 deletions parsec/core/gui/instance_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,12 @@ class InstanceWidget(QWidget):
join_organization_clicked = pyqtSignal()
create_organization_clicked = pyqtSignal()

def __init__(self, jobs_ctx, event_bus, config, **kwargs):
def __init__(self, jobs_ctx, event_bus, config, systray_notification, **kwargs):
super().__init__(**kwargs)
self.jobs_ctx = jobs_ctx
self.event_bus = event_bus
self.config = config
self.systray_notification = systray_notification

self.core = None
self.core_jobs_ctx = None
Expand Down Expand Up @@ -212,7 +213,11 @@ def login_with_password(self, key_file, password):
def show_central_widget(self):
self.clear_widgets()
central_widget = CentralWidget(
self.core, self.core_jobs_ctx, self.core.event_bus, parent=self
self.core,
self.core_jobs_ctx,
self.core.event_bus,
systray_notification=self.systray_notification,
parent=self,
)
self.layout().addWidget(central_widget)
central_widget.logout_requested.connect(self.logout)
Expand Down
6 changes: 3 additions & 3 deletions parsec/core/gui/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
class MainWindow(QMainWindow, Ui_MainWindow):
foreground_needed = pyqtSignal()
new_instance_needed = pyqtSignal(object)
systray_notification = pyqtSignal(str, str)
systray_notification = pyqtSignal(str, str, int)

TAB_NOTIFICATION_COLOR = QColor(46, 146, 208)
TAB_NOT_SELECTED_COLOR = QColor(123, 132, 163)
Expand Down Expand Up @@ -499,7 +499,7 @@ def _get_login_tab_index(self):
return -1

def add_new_tab(self):
tab = InstanceWidget(self.jobs_ctx, self.event_bus, self.config)
tab = InstanceWidget(self.jobs_ctx, self.event_bus, self.config, self.systray_notification)
tab.join_organization_clicked.connect(self._on_join_org_clicked)
tab.create_organization_clicked.connect(self._on_create_org_clicked)
idx = self.tab_center.addTab(tab, "")
Expand Down Expand Up @@ -658,7 +658,7 @@ def closeEvent(self, event):
if not self.minimize_on_close_notif_already_send:
self.minimize_on_close_notif_already_send = True
self.systray_notification.emit(
"Parsec", _("TEXT_TRAY_PARSEC_STILL_RUNNING_MESSAGE")
"Parsec", _("TEXT_TRAY_PARSEC_STILL_RUNNING_MESSAGE"), 2000
)
else:
if self.config.gui_confirmation_before_close and not self.force_close:
Expand Down
4 changes: 2 additions & 2 deletions parsec/core/gui/systray.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ def __init__(self, **kwargs):
self.activated.connect(self.on_activated)
self.show()

def on_systray_notification(self, title, msg):
self.showMessage(title, msg, msecs=2000)
def on_systray_notification(self, title, msg, msec=2000):
self.showMessage(title, msg, msecs=msec)

def on_activated(self, reason):
if reason == QSystemTrayIcon.DoubleClick:
Expand Down
3 changes: 3 additions & 0 deletions parsec/core/gui/tr/parsec_en.po
Original file line number Diff line number Diff line change
Expand Up @@ -1721,6 +1721,9 @@ msgstr "Connected"
msgid "TEXT_BACKEND_STATE_DISCONNECTED"
msgstr "Disconnected"

msgid "TEXT_SYSTRAY_BACKEND_DISCONNECT_organization"
msgstr "{organization}: Disconnected"

msgid "TEXT_BACKEND_STATE_API_MISMATCH_versions"
msgstr "Application incompatible with the server"

Expand Down
3 changes: 3 additions & 0 deletions parsec/core/gui/tr/parsec_fr.po
Original file line number Diff line number Diff line change
Expand Up @@ -1750,6 +1750,9 @@ msgstr "Connecté"
msgid "TEXT_BACKEND_STATE_DISCONNECTED"
msgstr "Déconnecté"

msgid "TEXT_SYSTRAY_BACKEND_DISCONNECT_organization"
msgstr "{organization}: Déconnecté"

msgid "TEXT_BACKEND_STATE_API_MISMATCH_versions"
msgstr "L'application n'est pas compatible avec le serveur"

Expand Down
27 changes: 27 additions & 0 deletions tests/core/gui/test_offline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Parsec Cloud (https://parsec.cloud) Copyright (c) AGPLv3 2019 Scille SAS

import pytest
from parsec.core.gui.lang import translate


@pytest.mark.gui
@pytest.mark.trio
async def test_offline_notification(aqtbot, running_backend, logged_gui):

central_widget = logged_gui.test_get_central_widget()
assert central_widget is not None

# Assert connected
assert central_widget.menu.label_connection_state.text() == translate(
"TEXT_BACKEND_STATE_CONNECTED"
)

# Assert offline
def _offline():
central_widget.menu.label_connection_state.text() == translate(
"TEXT_BACKEND_STATE_DISCONNECTED"
)

async with aqtbot.wait_signal(central_widget.systray_notification):
with running_backend.offline():
await aqtbot.wait_until(_offline)

0 comments on commit 5aca1b8

Please sign in to comment.