notification.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. package app
  2. import (
  3. "encoding/json"
  4. "github.com/maxence-charriere/go-app/v9/pkg/errors"
  5. )
  6. // A user notification.
  7. type Notification struct {
  8. // The title shown at the top of the notification window.
  9. Title string `json:"title"`
  10. // The URL path to navigate to when the notification is clicked.
  11. Path string `json:"path"`
  12. // The notification's language, as specified in
  13. // https://www.sitepoint.com/iso-2-letter-language-codes.
  14. Lang string `json:"lang,omitempty"`
  15. // The URL of the image used to represent the notification when there isn't
  16. // enough space to display the notification itself.
  17. Badge string `json:"badge,omitempty"`
  18. // The body text of the notification, which is displayed below the title.
  19. Body string `json:"body,omitempty"`
  20. // An identifying tag for the notification.
  21. Tag string `json:"tag,omitempty"`
  22. // The URL of an icon to be displayed in the notification.
  23. Icon string `json:"icon,omitempty"`
  24. // The URL of an image to be displayed in the notification.
  25. Image string `json:"image,omitempty"`
  26. // Arbitrary data that to be associated with the notification.
  27. //
  28. // The "goapp" key is reserved to go-app data.
  29. Data map[string]any `json:"data"`
  30. // Specifies whether the user should be notified after a new notification
  31. // replaces an old one.
  32. Renotify bool `json:"renotify,omitempty"`
  33. // Indicates whether a notification should remain active until the user
  34. // clicks or dismisses it, rather than closing automatically.
  35. RequireInteraction bool `json:"requireInteraction,omitempty"`
  36. // specifies whether the notification is silent (no sounds or vibrations
  37. // issued), regardless of the device settings.
  38. Silent bool `json:"silent,omitempty"`
  39. // A vibration pattern for the device's vibration hardware to emit with the
  40. // notification.
  41. //
  42. // See https://developer.mozilla.org/en-US/docs/Web/API/Vibration_API#vibration_patterns.
  43. Vibrate []int `json:"vibrate,omitempty"`
  44. // The actions to display in the notification.
  45. Actions []NotificationAction `json:"actions,omitempty"`
  46. }
  47. // A notification action.
  48. type NotificationAction struct {
  49. // The user action id to be displayed on the notification.
  50. Action string `json:"action"`
  51. // The action text to be shown to the user.
  52. Title string `json:"title"`
  53. // The URL of an icon to display with the action.
  54. Icon string `json:"icon,omitempty"`
  55. // The URL path to navigate to when the action is clicked.
  56. Path string `json:"path"`
  57. }
  58. // NotificationSubscription represents a PushSubscription object from the Push
  59. // API.
  60. type NotificationSubscription struct {
  61. Endpoint string `json:"endpoint"`
  62. Keys struct {
  63. Auth string `json:"auth"`
  64. P256dh string `json:"p256dh"`
  65. } `json:"keys"`
  66. }
  67. // NotificationPermission a permission to display notifications.
  68. type NotificationPermission string
  69. const (
  70. // The user notifications choice is unknown and therefore the browser acts
  71. // as if the value were denied.
  72. NotificationDefault NotificationPermission = "default"
  73. // The user accepts having notifications displayed.
  74. NotificationGranted NotificationPermission = "granted"
  75. // The user refuses to have notifications displayed.
  76. NotificationDenied NotificationPermission = "denied"
  77. // Notifications are not supported by the browser.
  78. NotificationNotSupported NotificationPermission = "unsupported"
  79. )
  80. type NotificationService struct {
  81. dispatcher Dispatcher
  82. }
  83. // Returns the current notification permission.
  84. func (s NotificationService) Permission() NotificationPermission {
  85. notification := Window().Get("Notification")
  86. if !notification.Truthy() {
  87. return NotificationNotSupported
  88. }
  89. return NotificationPermission(notification.Get("permission").String())
  90. }
  91. // Requests the user whether the app can use notifications.
  92. func (s NotificationService) RequestPermission() NotificationPermission {
  93. notification := Window().Get("Notification")
  94. if !notification.Truthy() {
  95. return NotificationNotSupported
  96. }
  97. permission := make(chan string, 1)
  98. defer close(permission)
  99. notification.Call("requestPermission").Then(func(v Value) {
  100. permission <- v.String()
  101. })
  102. return NotificationPermission(<-permission)
  103. }
  104. // Creates and display a user notification.
  105. func (s NotificationService) New(n Notification) {
  106. notification, _ := json.Marshal(n)
  107. Window().Call("goappNewNotification", string(notification))
  108. }
  109. // Returns a notification subscription with the given vap id.
  110. func (s NotificationService) Subscribe(vapIDPublicKey string) (NotificationSubscription, error) {
  111. if vapIDPublicKey == "" {
  112. return NotificationSubscription{}, errors.New("vapid public key is empty")
  113. }
  114. subc := make(chan string, 1)
  115. defer close(subc)
  116. Window().Call("goappSubscribePushNotifications", vapIDPublicKey).Then(func(v Value) {
  117. subc <- v.String()
  118. })
  119. jsSub := <-subc
  120. if jsSub == "" {
  121. return NotificationSubscription{}, errors.
  122. New("push notifications are not supported by the browser")
  123. }
  124. var sub NotificationSubscription
  125. err := json.Unmarshal([]byte(jsSub), &sub)
  126. if err != nil {
  127. return NotificationSubscription{}, errors.
  128. New("decoding push notification subscription failed").
  129. Wrap(err)
  130. }
  131. return sub, nil
  132. }