import logging import sys from PyQt6 import QtCore, QtDBus from vorta.store.models import SettingsModel try: from Foundation import NSUserNotification, NSUserNotificationCenter except ImportError: pass logger = logging.getLogger(__name__) class VortaNotifications: """ Usage: notifier = Notifications.pick()() notifier.deliver('blah', 'blah blah') """ @classmethod def pick(cls): if sys.platform == 'darwin': return DarwinNotifications() elif QtDBus.QDBusConnection.sessionBus().isConnected(): return DBusNotifications() else: logger.warning('could not pick valid notification class') return cls() def deliver(self, title, text, level='info'): """Dummy notifier if we're not on macOS or Linux notifier is not available.""" pass def notifications_suppressed(self, level): """Decide if notification is sent or not based on settings and level.""" if not SettingsModel.get(key='enable_notifications').value: logger.debug('notifications suppressed') return True if level == 'info' and not SettingsModel.get(key='enable_notifications_success').value: logger.debug('success notifications suppressed') return True logger.debug('notification not suppressed') return False class DarwinNotifications(VortaNotifications): """ Notify via notification center and pyobjc bridge. """ def deliver(self, title, text, level='info'): if self.notifications_suppressed(level): return notification = NSUserNotification.alloc().init() notification.setTitle_(title) notification.setInformativeText_(text) center = NSUserNotificationCenter.defaultUserNotificationCenter() if center is not None: # Only works when run from app bundle. return center.deliverNotification_(notification) class DBusNotifications(VortaNotifications): """ Use qt-dbus to send notifications. Adapted from http://codito.in/notifications-in-qt-over-dbus/ """ URGENCY = {'info': 1, 'error': 2} def __init__(self): pass def _dbus_notify(self, header, msg, level='info'): item = "org.freedesktop.Notifications" path = "/org/freedesktop/Notifications" interface = "org.freedesktop.Notifications" app_name = "vorta" id_replace = QtCore.QVariant(12321) id_replace.convert(QtCore.QMetaType(QtCore.QMetaType.Type.UInt.value)) icon = "com.borgbase.Vorta-symbolic" title = header text = msg actions_list = QtDBus.QDBusArgument([], QtCore.QMetaType.Type.QStringList.value) hint = {'urgency': self.URGENCY[level]} time = 5000 # milliseconds for display timeout bus = QtDBus.QDBusConnection.sessionBus() notify = QtDBus.QDBusInterface(item, path, interface, bus) if notify.isValid(): x = notify.call( # Call arguments for Notify interface need to match exactly: # https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html#command-notify QtDBus.QDBus.CallMode.AutoDetect, "Notify", app_name, id_replace, icon, title, text, actions_list, hint, time, ) if x.errorName(): logger.warning("Failed to send notification!") logger.warning(x.errorMessage()) else: logger.warning("Invalid dbus interface") def deliver(self, title, text, level='info'): if self.notifications_suppressed(level): return self._dbus_notify(title, text)