desktop-portal-0.2.2.0: src/Desktop/Portal/Notification.hs
module Desktop.Portal.Notification
( -- * Add Notification
AddNotificationOptions (..),
NotificationPriority (..),
NotificationIcon (..),
NotificationButton (..),
addNotificationOptions,
addNotification,
-- * Remove Notification
RemoveNotificationOptions (..),
removeNotification,
-- * Signals
NotificationActionInvokedCallback,
handleNotificationActionInvoked,
)
where
import Control.Exception (throwIO)
import Control.Monad (void)
import DBus (InterfaceName, Variant)
import DBus qualified
import DBus.Client qualified as DBus
import Data.ByteString.Lazy (ByteString)
import Data.Map (Map)
import Data.Map qualified as Map
import Data.Maybe (catMaybes, listToMaybe)
import Data.Text (Text)
import Desktop.Portal.Internal (Client, SignalHandler, callMethod, handleSignal)
import Desktop.Portal.Util (toVariantPair, toVariantPair')
import Prelude hiding (id)
data AddNotificationOptions = AddNotificationOptions
{ id :: Text,
title :: Maybe Text,
body :: Maybe Text,
priority :: Maybe NotificationPriority,
icon :: Maybe NotificationIcon,
defaultAction :: Maybe Text,
defaultActionTarget :: Maybe Variant,
buttons :: Maybe [NotificationButton]
}
deriving (Eq, Show)
data NotificationPriority
= NotificationPriorityLow
| NotificationPriorityNormal
| NotificationPriorityHigh
| NotificationPriorityUrgent
deriving (Eq, Show)
data NotificationIcon
= NotificationIconThemed [Text]
| NotificationIconBytes ByteString
deriving (Eq, Show)
data NotificationButton = NotificationButton
{ label_ :: Text,
action :: Text,
target :: Maybe Variant
}
deriving (Eq, Show)
addNotificationOptions ::
-- | The id of the notification
Text ->
AddNotificationOptions
addNotificationOptions id =
AddNotificationOptions
{ id,
title = Nothing,
body = Nothing,
priority = Nothing,
icon = Nothing,
defaultAction = Nothing,
defaultActionTarget = Nothing,
buttons = Nothing
}
newtype RemoveNotificationOptions = RemoveNotificationOptions
{id :: Text}
deriving (Eq, Show)
notificationInterface :: InterfaceName
notificationInterface = "org.freedesktop.portal.Notification"
addNotification :: Client -> AddNotificationOptions -> IO ()
addNotification client options =
void $ callMethod client notificationInterface "AddNotification" [id, optionsArg]
where
id = DBus.toVariant options.id
optionsArg =
DBus.toVariant . Map.fromList . catMaybes $
[ toVariantPair "title" options.title,
toVariantPair "body" options.body,
toVariantPair' encodePriority "priority" options.priority,
toVariantPair' encodeIcon "icon" options.icon,
toVariantPair "default-action" options.defaultAction,
("default-action-target",) <$> options.defaultActionTarget,
toVariantPair' (fmap encodeButton) "buttons" options.buttons
]
removeNotification :: Client -> RemoveNotificationOptions -> IO ()
removeNotification client options =
void $ callMethod client notificationInterface "RemoveNotification" [id]
where
id = DBus.toVariant options.id
type NotificationActionInvokedCallback =
-- | The id of the notification that was clicked.
Text ->
-- | The name of the action that was invoked.
Text ->
-- | The target parameter that goes along with the action, if any.
Maybe Variant ->
-- | A command to run when the action is invoked.
IO ()
-- | Listen for notification actions being invoked.
handleNotificationActionInvoked :: Client -> NotificationActionInvokedCallback -> IO SignalHandler
handleNotificationActionInvoked client handler =
handleSignal client notificationInterface "ActionInvoked" $ \signalBody -> do
case signalBody of
[notificationId, actionName, parameter]
| Just notificationId' <- DBus.fromVariant notificationId,
Just actionName' <- DBus.fromVariant actionName,
Just parameter' <- DBus.fromVariant parameter -> do
handler notificationId' actionName' (listToMaybe parameter')
_ ->
throwIO . DBus.clientError $ "handleNotificationActionInvoked: could not parse signal body: " <> show signalBody
encodePriority :: NotificationPriority -> Text
encodePriority = \case
NotificationPriorityLow -> "low"
NotificationPriorityNormal -> "normal"
NotificationPriorityHigh -> "high"
NotificationPriorityUrgent -> "urgent"
encodeIcon :: NotificationIcon -> (Text, Variant)
encodeIcon = \case
NotificationIconThemed iconNames -> ("themed", DBus.toVariant iconNames)
NotificationIconBytes bytes -> ("bytes", DBus.toVariant bytes)
encodeButton :: NotificationButton -> Map Text Variant
encodeButton button =
Map.fromList . catMaybes $
[ toVariantPair "label" (Just button.label_),
toVariantPair "action" (Just button.action),
toVariantPair "target" button.target
]