commit 4f76e2711583dd0eaee1c9f811add4ec024ea921
parent 3519b3288395b26f03742febec55140d58574c69
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date: Fri, 17 Jan 2025 16:00:08 +0800
notify: simplify api but using callback identity
Because the callback is associated with the instance of the
notification, we don't actually need to fully qualify the callback
arguments with it's ID or default payload values.
Those values are either assumed or captured by the closure.
As such we can remove some of the data plumbing.
Signed-off-by: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Diffstat:
5 files changed, 31 insertions(+), 99 deletions(-)
diff --git a/cmd/notify/main.go b/cmd/notify/main.go
@@ -26,7 +26,7 @@ func main() {
flag.StringVar(&title, "title", "title", "title text of notification")
flag.StringVar(&body, "body", "body", "body text of notification")
- flag.StringVar(&icon, "icon", "./cmd/notify/puzzle.png", "path to icon file for notification")
+ flag.StringVar(&icon, "icon", "./puzzle.png", "path to icon file for notification")
flag.StringVar(&payload, "payload", "example-payload", "data to be returned upon activation")
flag.Parse()
@@ -52,11 +52,9 @@ func main() {
}
if err := nativenotify.Push(nativenotify.Notification{
- ID: "text-message",
- Title: title,
- Body: body,
- Icon: icon,
- AppPayload: payload,
+ Title: title,
+ Body: body,
+ Icon: icon,
TextActions: []nativenotify.TextAction{
{
ID: "reply",
@@ -67,16 +65,13 @@ func main() {
},
ButtonActions: []nativenotify.ButtonAction{
{
- ID: "like",
- LabelText: "Like",
- AppPayload: "@jack",
+ ID: "like",
+ LabelText: "Like",
+ Value: "@jack",
},
},
- Callback: func(err error, id string, userData map[string]string) {
- slog.Info("callback", "id", id, "userData", userData)
- if err != nil {
- slog.Error("callback error", "err", err)
- }
+ Callback: func(action, value string) {
+ slog.Info("callback", "action", action, "value", value)
},
}); err != nil {
slog.Error("pushing notification", "err", err)
diff --git a/notify.go b/notify.go
@@ -23,25 +23,12 @@ import (
)
// Callback is executed when the user interacts with a given notification.
-//
-// [id] names the parent notification that was activated.
-//
-// [data] contains user input data. Either the text input, the button payload
-// or the parent notification payload. Data should be inspected to understand
-// what part of the notification was activated.
-type Callback func(err error, id string, data map[string]string)
+// [action] is the activated action.
+// [value] is any associated value for that action.
+type Callback func(action, value string)
// Notification describes the notification.
type Notification struct {
- // ID names this notification. This value will appear as the first string argument
- // to the callback.
- ID string
-
- // AppPayload is passed to the callback upon activation under the key "default".
- // No matter what part of the notification was activated, this payload will always
- // be provided to the callback.
- AppPayload string
-
// Callback is called upon activation.
Callback Callback
@@ -85,8 +72,8 @@ type TextAction struct {
type ButtonAction struct {
// ID names the action. The [AppPayload] will appear in the user data keyed by this ID.
ID string
- // AppPayload is provided to the callback if this action is activated.
- AppPayload string
+ // Value is provided to the callback if this action is activated.
+ Value string
// LabelText describes the text content of this button action.
LabelText string
}
@@ -117,9 +104,6 @@ func Setup(cfg Config) error {
// Push a notification to the operating system.
func Push(n Notification) error {
- if n.ID == "" {
- return fmt.Errorf("notification requires ID")
- }
for ii, a := range n.ButtonActions {
if a.ID == "" {
return fmt.Errorf("buttonaction %d requires ID", ii)
diff --git a/notify_darwin.go b/notify_darwin.go
@@ -24,20 +24,8 @@ func setup(cfg Config) error {
actionID := decode(actionIDEncoded)
actionArgs := decode(actionArgsEncoded)
- data := map[string]string{}
-
if args.UserText != "" {
- data[actionID] = args.UserText
- } else if actionArgs != "" {
- data[actionID] = actionArgs
- }
-
- // Map the user data map to the key-value slice style.
- for k, v := range args.UserData {
- if k == "id" {
- continue
- }
- data[k] = v
+ actionArgs = args.UserText
}
fn, ok := callbacksTake(&callbacks, id)
@@ -45,7 +33,7 @@ func setup(cfg Config) error {
return
}
- fn(args.Err, actionID, data)
+ fn(actionID, actionArgs)
})
return nil
@@ -60,12 +48,11 @@ func push(n Notification) (err error) {
userData = make(darwinnotify.UserData)
)
- userData["default"] = n.AppPayload
userData["id"] = strconv.FormatInt(id, 10)
for _, button := range n.ButtonActions {
buttons = append(buttons, darwinnotify.Action{
- ID: fmt.Sprintf("%s-%s", encode(button.ID), encode(button.AppPayload)),
+ ID: fmt.Sprintf("%s-%s", encode(button.ID), encode(button.Value)),
Title: button.LabelText,
})
}
@@ -94,9 +81,7 @@ func push(n Notification) (err error) {
UserData: userData,
})
- callbacksPut(&callbacks, strconv.FormatInt(id, 10), func(err error, id string, data map[string]string) {
- n.Callback(err, n.ID, data)
- })
+ callbacksPut(&callbacks, strconv.FormatInt(id, 10), n.Callback)
return nil
}
diff --git a/notify_linux.go b/notify_linux.go
@@ -22,26 +22,11 @@ func setup(cfg Config) error {
cfg.Linux.AppName,
cfg.Linux.AppIcon,
func(id, action string, platformData map[string]dbus.Variant, target, response dbus.Variant, err error) {
- data := make(map[string]string)
-
- data[action] = target.String()
-
- if r := response.String(); r != "" {
- data["response"] = r
- }
-
- for k, v := range platformData {
- if s := v.String(); s != "" {
- data[k] = s
- }
- }
-
fn, ok := callbacksTake(&callbacks, id)
if !ok || fn == nil {
return
}
-
- fn(err, id, data)
+ fn(action, target.String())
},
)
if err != nil {
@@ -68,7 +53,7 @@ func push(n Notification) (err error) {
buttons = append(buttons, shout.Button{
Action: a.ID,
Label: a.LabelText,
- Target: a.AppPayload,
+ Target: a.Value,
})
}
@@ -79,22 +64,16 @@ func push(n Notification) (err error) {
Markup: false,
IconPath: n.Icon,
Priority: shout.Normal,
- DefaultAction: n.ID,
+ DefaultAction: "default",
DefaultActionLabel: "",
- DefaultActionTarget: dbus.MakeVariant(n.AppPayload),
+ DefaultActionTarget: dbus.Variant{},
Buttons: buttons,
ExpirationTimeout: 0,
}); err != nil {
return fmt.Errorf("sending notification: %w", err)
}
- callbacksPut(&callbacks, strconv.FormatInt(id, 10), func(err error, id string, userData map[string]string) {
- if userData == nil {
- userData = make(map[string]string)
- }
- userData["default"] = n.AppPayload
- n.Callback(err, n.ID, userData)
- })
+ callbacksPut(&callbacks, strconv.FormatInt(id, 10), n.Callback)
return nil
}
diff --git a/notify_windows.go b/notify_windows.go
@@ -21,24 +21,20 @@ func setup(cfg Config) error {
actionID := decode(actionIDEncoded)
actionArgs := decode(actionArgsEncoded)
- data := make(map[string]string)
-
+ // If the action was a text input, or a selection, grab the value for it.
+ // If the action was a button, the actionArgs will contain the value.
for _, ud := range userdata {
- if ud.Value != "" {
- data[ud.Key] = ud.Value
+ if ud.Key == actionID {
+ actionArgs = ud.Value
}
}
- if actionID != "" {
- data[actionID] = actionArgs
- }
-
fn, ok := callbacksTake(&callbacks, id)
if !ok || fn == nil {
return
}
- fn(nil, args, data)
+ fn(actionID, actionArgs)
})
return nil
}
@@ -61,7 +57,7 @@ func push(n Notification) (err error) {
for _, a := range n.ButtonActions {
actions = append(actions, windowsnotify.Action{
Content: a.LabelText,
- Arguments: fmt.Sprintf("%d-%s-%s", id, encode(a.ID), encode(a.AppPayload)),
+ Arguments: fmt.Sprintf("%d-%s-%s", id, encode(a.ID), encode(a.Value)),
})
}
@@ -85,19 +81,12 @@ func push(n Notification) (err error) {
Body: n.Body,
Icon: n.Icon,
ActivationType: windowsnotify.Foreground,
- ActivationArguments: fmt.Sprintf("%d-%s", id, encode(n.ID)),
+ ActivationArguments: strconv.FormatInt(id, 10),
Actions: actions,
Inputs: inputs,
}
- // This closure ensures that the outer notification ID and payload is always passed to the callback.
- // The action data will appear in [userData].
- callbacksPut(&callbacks, strconv.FormatInt(id, 10), func(err error, args string, userData map[string]string) {
- if n.AppPayload != "" {
- userData["default"] = n.AppPayload
- }
- n.Callback(err, n.ID, userData)
- })
+ callbacksPut(&callbacks, strconv.FormatInt(id, 10), n.Callback)
return tn.Push()
}