diff --git a/v3/examples/notifications/frontend/index.html b/v3/examples/notifications/frontend/index.html deleted file mode 100644 index 88daa5e2f..000000000 --- a/v3/examples/notifications/frontend/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - Wails App - - -
-
- - - - - - -
-

Wails + Javascript

- -
- - - diff --git a/v3/examples/notifications/frontend/main.js b/v3/examples/notifications/frontend/main.js deleted file mode 100644 index 18dd0214c..000000000 --- a/v3/examples/notifications/frontend/main.js +++ /dev/null @@ -1,67 +0,0 @@ -import { GreetService } from "./bindings/notifications"; -import { NotificationService } from "./bindings/github.com/wailsapp/wails/v3/pkg/services/notification"; -import { Events } from "@wailsio/runtime"; - -const resultElement = document.getElementById('result'); -const timeElement = document.getElementById('time'); -const notificationsElement = document.getElementById('notifications'); - -const nofitications = new Map(); - -window.doGreet = () => { - let name = document.getElementById('name').value; - if (!name) { - name = 'anonymous'; - } - GreetService.Greet(name).then((result) => { - resultElement.innerText = result; - }).catch((err) => { - console.log(err); - }); -} - -window.sendNotification = async () => { - const granted = await NotificationService.CheckNotificationAuthorization(); - if (granted) { - await NotificationService.SendNotification("some-uuid-fronted", "Frontend Notificaiton", "", "Notificaiton sent through JS!"); - } -} - -window.sendComplexNotification = async () => { - const granted = await NotificationService.CheckNotificationAuthorization(); - if (granted) { - await NotificationService.RegisterNotificationCategory({ - id: "FRONTEND_NOTIF", - actions: [ - { id: "VIEW_ACTION", title: "View" }, - { id: "MARK_READ_ACTION", title: "Mark as Read" }, - { id: "DELETE_ACTION", title: "Delete", destructive: true }, - ], - hasReplyField: true, - replyButtonTitle: "Reply", - replyPlaceholder: "Reply to frontend...", - }); - - await NotificationService.SendNotificationWithActions({ - id: "some-uuid-complex", - title: "Complex Frontend Notification", - subtitle: "From: Jane Doe", - body: "Is it rainging today where you are?", - categoryId: "FRONTEND_NOTIF", - data: { - messageId: "msg-456", - senderId: "user-456", - timestamp: Date.now(), - } - }); - } -} - -Events.On('time', (time) => { - timeElement.innerText = time.data; -}); - -Events.On("notification", (data) => { - nofitications.set(data.identifier, data); - notificationsElement.innerText = Array.from(nofitications.values()).map(notification => JSON.stringify(notification)).join(", "); -}); \ No newline at end of file diff --git a/v3/examples/notifications/frontend/package.json b/v3/examples/notifications/frontend/package.json deleted file mode 100644 index 9ae87549e..000000000 --- a/v3/examples/notifications/frontend/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "frontend", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build:dev": "vite build --minify false --mode development", - "build": "vite build --mode production", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^5.0.0", - "@wailsio/runtime": "latest" - } -} \ No newline at end of file diff --git a/v3/examples/notifications/frontend/public/Inter-Medium.ttf b/v3/examples/notifications/frontend/public/Inter-Medium.ttf deleted file mode 100644 index a01f3777a..000000000 Binary files a/v3/examples/notifications/frontend/public/Inter-Medium.ttf and /dev/null differ diff --git a/v3/examples/notifications/frontend/public/javascript.svg b/v3/examples/notifications/frontend/public/javascript.svg deleted file mode 100644 index f9abb2b72..000000000 --- a/v3/examples/notifications/frontend/public/javascript.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/v3/examples/notifications/frontend/public/style.css b/v3/examples/notifications/frontend/public/style.css deleted file mode 100644 index 127799eda..000000000 --- a/v3/examples/notifications/frontend/public/style.css +++ /dev/null @@ -1,160 +0,0 @@ -:root { - font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", - "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: rgba(27, 38, 54, 1); - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; -} - -* { - user-select: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; -} - -@font-face { - font-family: "Inter"; - font-style: normal; - font-weight: 400; - src: local(""), - url("./Inter-Medium.ttf") format("truetype"); -} - -h3 { - font-size: 3em; - line-height: 1.1; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} - -a:hover { - color: #535bf2; -} - -button { - /* width: 60px; */ - height: 30px; - line-height: 30px; - border-radius: 3px; - border: none; - margin: 0 0 0 20px; - padding: 0 8px; - cursor: pointer; -} - -.result { - height: 20px; - line-height: 20px; -} - -body { - margin: 0; - display: flex; - place-items: center; - place-content: center; - min-width: 320px; - min-height: 100vh; -} - -.container { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -#app { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; -} - -.logo:hover { - filter: drop-shadow(0 0 2em #e80000aa); -} - -.logo.vanilla:hover { - filter: drop-shadow(0 0 2em #f7df1eaa); -} - -.result { - height: 20px; - line-height: 20px; - margin: 1.5rem auto; - text-align: center; -} - -.footer { - margin-top: 1rem; - align-content: center; - text-align: center; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - - a:hover { - color: #747bff; - } - - button { - background-color: #f9f9f9; - } -} - - -.input-box .btn:hover { - background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%); - color: #333333; -} - -.input-box .input { - border: none; - border-radius: 3px; - outline: none; - height: 30px; - line-height: 30px; - padding: 0 10px; - color: black; - background-color: rgba(240, 240, 240, 1); - -webkit-font-smoothing: antialiased; -} - -.input-box .input:hover { - border: none; - background-color: rgba(255, 255, 255, 1); -} - -.input-box .input:focus { - border: none; - background-color: rgba(255, 255, 255, 1); -} \ No newline at end of file diff --git a/v3/examples/notifications/frontend/public/wails.png b/v3/examples/notifications/frontend/public/wails.png deleted file mode 100644 index 8bdf42483..000000000 Binary files a/v3/examples/notifications/frontend/public/wails.png and /dev/null differ diff --git a/v3/examples/notifications/main.go b/v3/examples/notifications/main.go deleted file mode 100644 index 35fb7b06b..000000000 --- a/v3/examples/notifications/main.go +++ /dev/null @@ -1,135 +0,0 @@ -package main - -import ( - _ "embed" - "fmt" - "log" - "time" - - "github.com/wailsapp/wails/v3/pkg/application" - "github.com/wailsapp/wails/v3/pkg/events" - "github.com/wailsapp/wails/v3/pkg/services/notification" -) - -func main() { - app := application.New(application.Options{ - Name: "Notifications Demo", - Description: "A test of macOS notifications", - Assets: application.AlphaAssets, - Services: []application.Service{ - application.NewService(¬ification.NotificationService{}), - }, - }) - - app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ - Width: 500, - Height: 800, - }) - - app.OnApplicationEvent(events.Mac.ApplicationDidFinishLaunching, func(event *application.ApplicationEvent) { - // Request pemission to send notifications - granted, err := application.RequestUserNotificationAuthorization() - if err != nil { - log.Default().Printf("WARNING: %s\n", err) - } - - if granted { - // Send notification with no actions - err = application.SendNotification("some-uuid", "Title", "", "body!") - if err != nil { - log.Default().Printf("WARNING: %s\n", err) - } - - err = application.RegisterNotificationCategory(application.NotificationCategory{ - ID: "MESSAGE_CATEGORY", - Actions: []application.NotificationAction{ - {ID: "VIEW_ACTION", Title: "View"}, - {ID: "MARK_READ_ACTION", Title: "Mark as Read"}, - {ID: "DELETE_ACTION", Title: "Delete", Destructive: true}, - }, - HasReplyField: true, - ReplyPlaceholder: "Type your reply...", - ReplyButtonTitle: "Reply", - }) - if err != nil { - log.Default().Printf("WARNING: %s\n", err) - } - - err = application.SendNotificationWithActions(application.NotificationOptions{ - ID: "some-other-uuid", - Title: "New Message", - Subtitle: "From: Jane Doe", - Body: "Is it raining today where you are?", - CategoryID: "MESSAGE_CATEGORY", - Data: map[string]interface{}{ - "messageId": "msg-123", - "senderId": "user-123", - "timestamp": time.Now().Unix(), - }, - }) - if err != nil { - log.Default().Printf("WARNING: %s\n", err) - } - } - }) - - app.OnApplicationEvent(events.Mac.DidReceiveNotificationResponse, func(event *application.ApplicationEvent) { - data := event.Context().GetData() - - // Parse data received - if data != nil { - if identifier, ok := data["identifier"].(string); ok { - fmt.Printf("Notification identifier: %s\n", identifier) - } - - if actionIdentifier, ok := data["actionIdentifier"].(string); ok { - fmt.Printf("Action Identifier: %s\n", actionIdentifier) - } - - if userText, ok := data["userText"].(string); ok { - fmt.Printf("User replied: %s\n", userText) - } - - if userInfo, ok := data["userInfo"].(map[string]interface{}); ok { - fmt.Printf("Custom data: %+v\n", userInfo) - } - - // Send notification to JS - app.EmitEvent("notification", data) - } - }) - - go func() { - time.Sleep(time.Second * 5) - // Sometime later check if you are still authorized - granted, err := application.CheckNotificationAuthorization() - if err != nil { - log.Default().Printf("WARNING: %s\n", err) - } - println(granted) - - // Sometime later remove delivered notification by identifier - err = application.RemoveDeliveredNotification("some-uuid") - if err != nil { - log.Default().Printf("WARNING: %s\n", err) - } - }() - - go func() { - time.Sleep(time.Second * 10) - // Sometime later remove all pending and delivered notifications - err := application.RemoveAllPendingNotifications() - if err != nil { - log.Default().Printf("WARNING: %s\n", err) - } - err = application.RemoveAllDeliveredNotifications() - if err != nil { - log.Default().Printf("WARNING: %s\n", err) - } - }() - - err := app.Run() - if err != nil { - log.Fatal(err) - } -} diff --git a/v3/examples/services/assets/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/index.js b/v3/examples/services/assets/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/index.js new file mode 100644 index 000000000..eb8893845 --- /dev/null +++ b/v3/examples/services/assets/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/index.js @@ -0,0 +1,25 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as Service from "./service.js"; +export { + Service +}; + +import * as $models from "./models.js"; + +/** + * NotificationAction represents an action button for a notification + * @typedef {$models.NotificationAction} NotificationAction + */ + +/** + * NotificationCategory groups actions for notifications + * @typedef {$models.NotificationCategory} NotificationCategory + */ + +/** + * NotificationOptions contains configuration for a notification + * @typedef {$models.NotificationOptions} NotificationOptions + */ diff --git a/v3/examples/services/assets/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/models.js b/v3/examples/services/assets/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/models.js new file mode 100644 index 000000000..2525e0f38 --- /dev/null +++ b/v3/examples/services/assets/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/models.js @@ -0,0 +1,37 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import {Create as $Create} from "@wailsio/runtime"; + +/** + * NotificationAction represents an action button for a notification + * @typedef {Object} NotificationAction + * @property {string} id + * @property {string} title + * @property {boolean} [destructive] + * @property {boolean} [authenticationRequired] + */ + +/** + * NotificationCategory groups actions for notifications + * @typedef {Object} NotificationCategory + * @property {string} id + * @property {NotificationAction[]} actions + * @property {boolean} [hasReplyField] + * @property {string} [replyPlaceholder] + * @property {string} [replyButtonTitle] + */ + +/** + * NotificationOptions contains configuration for a notification + * @typedef {Object} NotificationOptions + * @property {string} id + * @property {string} title + * @property {string} [subtitle] + * @property {string} body + * @property {string} [categoryId] + * @property {{ [_: string]: any }} [data] + */ diff --git a/v3/examples/services/assets/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/service.js b/v3/examples/services/assets/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/service.js new file mode 100644 index 000000000..5c91a1c77 --- /dev/null +++ b/v3/examples/services/assets/bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/service.js @@ -0,0 +1,98 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import {Call as $Call, Create as $Create} from "@wailsio/runtime"; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import * as $models from "./models.js"; + +/** + * CheckNotificationAuthorization checks current permission status + * @returns {Promise & { cancel(): void }} + */ +export function CheckNotificationAuthorization() { + let $resultPromise = /** @type {any} */($Call.ByID(2789931702)); + return $resultPromise; +} + +/** + * RegisterNotificationCategory registers a category with actions and optional reply field + * @param {$models.NotificationCategory} category + * @returns {Promise & { cancel(): void }} + */ +export function RegisterNotificationCategory(category) { + let $resultPromise = /** @type {any} */($Call.ByID(2679064664, category)); + return $resultPromise; +} + +/** + * @returns {Promise & { cancel(): void }} + */ +export function RemoveAllDeliveredNotifications() { + let $resultPromise = /** @type {any} */($Call.ByID(384520397)); + return $resultPromise; +} + +/** + * RemoveAllPendingNotifications removes all pending notifications + * @returns {Promise & { cancel(): void }} + */ +export function RemoveAllPendingNotifications() { + let $resultPromise = /** @type {any} */($Call.ByID(1423986276)); + return $resultPromise; +} + +/** + * @param {string} identifier + * @returns {Promise & { cancel(): void }} + */ +export function RemoveDeliveredNotification(identifier) { + let $resultPromise = /** @type {any} */($Call.ByID(149440045, identifier)); + return $resultPromise; +} + +/** + * RemovePendingNotification removes a specific pending notification + * @param {string} identifier + * @returns {Promise & { cancel(): void }} + */ +export function RemovePendingNotification(identifier) { + let $resultPromise = /** @type {any} */($Call.ByID(3872412470, identifier)); + return $resultPromise; +} + +/** + * RequestUserNotificationAuthorization requests permission for notifications. + * @returns {Promise & { cancel(): void }} + */ +export function RequestUserNotificationAuthorization() { + let $resultPromise = /** @type {any} */($Call.ByID(3412125712)); + return $resultPromise; +} + +/** + * SendNotification sends a notification with the given identifier, title, subtitle, and body. + * @param {string} identifier + * @param {string} title + * @param {string} subtitle + * @param {string} body + * @returns {Promise & { cancel(): void }} + */ +export function SendNotification(identifier, title, subtitle, body) { + let $resultPromise = /** @type {any} */($Call.ByID(2246903123, identifier, title, subtitle, body)); + return $resultPromise; +} + +/** + * SendNotificationWithActions sends a notification with the specified actions + * @param {$models.NotificationOptions} options + * @returns {Promise & { cancel(): void }} + */ +export function SendNotificationWithActions(options) { + let $resultPromise = /** @type {any} */($Call.ByID(1615199806, options)); + return $resultPromise; +} diff --git a/v3/examples/services/assets/index.html b/v3/examples/services/assets/index.html index 67746fdec..24a372593 100644 --- a/v3/examples/services/assets/index.html +++ b/v3/examples/services/assets/index.html @@ -10,6 +10,13 @@ import * as kvstore from './bindings/github.com/wailsapp/wails/v3/pkg/services/kvstore/keyvaluestore.js'; import {Debug, Info, Warning, Error} from './bindings/github.com/wailsapp/wails/v3/pkg/services/log/loggerservice.js'; import * as hash from './bindings/github.com/wailsapp/wails/v3/examples/services/hashes/service.js'; + import * as notifications from "./bindings/github.com/wailsapp/wails/v3/pkg/services/notifications/service.js" + + notifications.RequestUserNotificationAuthorization().then((granted) => { + if (granted) { + notifications.SendNotification("some-uuid-fronted", "Frontend Notificaiton", "", "Notificaiton sent through JS!"); + } + }); function runHash() { let hashstring = document.getElementById("hashstring").value; diff --git a/v3/examples/services/main.go b/v3/examples/services/main.go index a4ebb6bf4..6bc020c8a 100644 --- a/v3/examples/services/main.go +++ b/v3/examples/services/main.go @@ -2,16 +2,18 @@ package main import ( "embed" + "log/slog" + "os" + "path/filepath" + "runtime" + "github.com/wailsapp/wails/v3/examples/services/hashes" "github.com/wailsapp/wails/v3/pkg/application" "github.com/wailsapp/wails/v3/pkg/services/fileserver" "github.com/wailsapp/wails/v3/pkg/services/kvstore" "github.com/wailsapp/wails/v3/pkg/services/log" + "github.com/wailsapp/wails/v3/pkg/services/notifications" "github.com/wailsapp/wails/v3/pkg/services/sqlite" - "log/slog" - "os" - "path/filepath" - "runtime" ) //go:embed assets/* @@ -48,6 +50,7 @@ func main() { }), application.ServiceOptions{ Route: "/files", }), + application.NewService(notifications.New()), }, Assets: application.AssetOptions{ Handler: application.BundledAssetFileServer(assets), diff --git a/v3/pkg/application/notifications_darwin.go b/v3/pkg/application/notifications_darwin.go deleted file mode 100644 index e04075238..000000000 --- a/v3/pkg/application/notifications_darwin.go +++ /dev/null @@ -1,177 +0,0 @@ -//go:build darwin - -package application - -/* -#cgo CFLAGS: -mmacosx-version-min=10.14 -x objective-c -#cgo LDFLAGS: -framework Cocoa -mmacosx-version-min=10.14 -framework UserNotifications -#import "notifications_darwin.h" -*/ -import "C" -import ( - "encoding/json" - "fmt" - "unsafe" -) - -// NotificationAction represents a button in a notification -type NotificationAction struct { - ID string `json:"id"` - Title string `json:"title"` - Destructive bool `json:"destructive,omitempty"` - AuthenticationRequired bool `json:"authenticationRequired,omitempty"` -} - -// NotificationCategory groups actions for notifications -type NotificationCategory struct { - ID string `json:"id"` - Actions []NotificationAction `json:"actions"` - HasReplyField bool `json:"hasReplyField,omitempty"` - ReplyPlaceholder string `json:"replyPlaceholder,omitempty"` - ReplyButtonTitle string `json:"replyButtonTitle,omitempty"` -} - -// NotificationOptions contains configuration for a notification -type NotificationOptions struct { - ID string `json:"id"` - Title string `json:"title"` - Subtitle string `json:"subtitle,omitempty"` - Body string `json:"body"` - CategoryID string `json:"categoryId,omitempty"` - Data map[string]interface{} `json:"data,omitempty"` -} - -// Check if the app has a valid bundle identifier -func CheckBundleIdentifier() bool { - return bool(C.checkBundleIdentifier()) -} - -// RequestUserNotificationAuthorization requests permission for notifications. -func RequestUserNotificationAuthorization() (bool, error) { - if !CheckBundleIdentifier() { - return false, fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") - } - result := C.requestUserNotificationAuthorization(nil) - return result == true, nil -} - -// CheckNotificationAuthorization checks current permission status -func CheckNotificationAuthorization() (bool, error) { - if !CheckBundleIdentifier() { - return false, fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") - } - return bool(C.checkNotificationAuthorization()), nil -} - -// SendNotification sends a notification with the given identifier, title, subtitle, and body. -func SendNotification(identifier, title, subtitle, body string) error { - if !CheckBundleIdentifier() { - return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") - } - cIdentifier := C.CString(identifier) - cTitle := C.CString(title) - cSubtitle := C.CString(subtitle) - cBody := C.CString(body) - defer C.free(unsafe.Pointer(cIdentifier)) - defer C.free(unsafe.Pointer(cTitle)) - defer C.free(unsafe.Pointer(cSubtitle)) - defer C.free(unsafe.Pointer(cBody)) - - C.sendNotification(cIdentifier, cTitle, cSubtitle, cBody, nil) - return nil -} - -// SendNotificationWithActions sends a notification with the specified actions -func SendNotificationWithActions(options NotificationOptions) error { - if !CheckBundleIdentifier() { - return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") - } - cIdentifier := C.CString(options.ID) - cTitle := C.CString(options.Title) - cSubtitle := C.CString(options.Subtitle) - cBody := C.CString(options.Body) - cCategoryID := C.CString(options.CategoryID) - defer C.free(unsafe.Pointer(cIdentifier)) - defer C.free(unsafe.Pointer(cTitle)) - defer C.free(unsafe.Pointer(cSubtitle)) - defer C.free(unsafe.Pointer(cBody)) - defer C.free(unsafe.Pointer(cCategoryID)) - - var cActionsJSON *C.char - if options.Data != nil { - jsonData, err := json.Marshal(options.Data) - if err == nil { - cActionsJSON = C.CString(string(jsonData)) - defer C.free(unsafe.Pointer(cActionsJSON)) - } - } - - C.sendNotificationWithActions(cIdentifier, cTitle, cSubtitle, cBody, cCategoryID, cActionsJSON, nil) - return nil -} - -// RegisterNotificationCategory registers a category with actions and optional reply field -func RegisterNotificationCategory(category NotificationCategory) error { - if !CheckBundleIdentifier() { - return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") - } - cCategoryID := C.CString(category.ID) - defer C.free(unsafe.Pointer(cCategoryID)) - - actionsJSON, err := json.Marshal(category.Actions) - if err != nil { - return err - } - cActionsJSON := C.CString(string(actionsJSON)) - defer C.free(unsafe.Pointer(cActionsJSON)) - - var cReplyPlaceholder, cReplyButtonTitle *C.char - if category.HasReplyField { - cReplyPlaceholder = C.CString(category.ReplyPlaceholder) - cReplyButtonTitle = C.CString(category.ReplyButtonTitle) - defer C.free(unsafe.Pointer(cReplyPlaceholder)) - defer C.free(unsafe.Pointer(cReplyButtonTitle)) - } - - C.registerNotificationCategory(cCategoryID, cActionsJSON, C.bool(category.HasReplyField), - cReplyPlaceholder, cReplyButtonTitle) - return nil -} - -// RemoveAllPendingNotifications removes all pending notifications -func RemoveAllPendingNotifications() error { - if !CheckBundleIdentifier() { - return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") - } - C.removeAllPendingNotifications() - return nil -} - -// RemovePendingNotification removes a specific pending notification -func RemovePendingNotification(identifier string) error { - if !CheckBundleIdentifier() { - return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") - } - cIdentifier := C.CString(identifier) - defer C.free(unsafe.Pointer(cIdentifier)) - C.removePendingNotification(cIdentifier) - return nil -} - -func RemoveAllDeliveredNotifications() error { - if !CheckBundleIdentifier() { - return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") - } - C.removeAllDeliveredNotifications() - return nil -} - -func RemoveDeliveredNotification(identifier string) error { - if !CheckBundleIdentifier() { - return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") - } - cIdentifier := C.CString(identifier) - defer C.free(unsafe.Pointer(cIdentifier)) - C.removeDeliveredNotification(cIdentifier) - return nil -} diff --git a/v3/pkg/services/notification/notification.go b/v3/pkg/services/notifications/notifications.go similarity index 83% rename from v3/pkg/services/notification/notification.go rename to v3/pkg/services/notifications/notifications.go index 987e4d438..8f700daf5 100644 --- a/v3/pkg/services/notification/notification.go +++ b/v3/pkg/services/notifications/notifications.go @@ -1,11 +1,11 @@ //go:build darwin -package notification +package notifications /* #cgo CFLAGS: -mmacosx-version-min=10.14 -x objective-c #cgo LDFLAGS: -framework Cocoa -mmacosx-version-min=10.14 -framework UserNotifications -#import "../../application/notifications_darwin.h" +#import "./notifications_darwin.h" */ import "C" import ( @@ -17,11 +17,11 @@ import ( "github.com/wailsapp/wails/v3/pkg/application" ) -type NotificationService struct { +type Service struct { } // NotificationAction represents an action button for a notification -type NotificationAction struct { +type NotificationAction = struct { ID string `json:"id"` Title string `json:"title"` Destructive bool `json:"destructive,omitempty"` @@ -29,7 +29,7 @@ type NotificationAction struct { } // NotificationCategory groups actions for notifications -type NotificationCategory struct { +type NotificationCategory = struct { ID string `json:"id"` Actions []NotificationAction `json:"actions"` HasReplyField bool `json:"hasReplyField,omitempty"` @@ -38,7 +38,7 @@ type NotificationCategory struct { } // NotificationOptions contains configuration for a notification -type NotificationOptions struct { +type NotificationOptions = struct { ID string `json:"id"` Title string `json:"title"` Subtitle string `json:"subtitle,omitempty"` @@ -47,17 +47,21 @@ type NotificationOptions struct { Data map[string]interface{} `json:"data,omitempty"` } +func New() *Service { + return &Service{} +} + func CheckBundleIdentifier() bool { return bool(C.checkBundleIdentifier()) } // ServiceName returns the name of the service -func (ns *NotificationService) ServiceName() string { +func (ns *Service) ServiceName() string { return "github.com/wailsapp/wails/v3/services/notifications" } // ServiceStartup is called when the service is loaded -func (ns *NotificationService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { +func (ns *Service) ServiceStartup(ctx context.Context, options application.ServiceOptions) error { if !CheckBundleIdentifier() { return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") } @@ -65,12 +69,12 @@ func (ns *NotificationService) ServiceStartup(ctx context.Context, options appli } // ServiceShutdown is called when the service is unloaded -func (ns *NotificationService) ServiceShutdown() error { +func (ns *Service) ServiceShutdown() error { return nil } // RequestUserNotificationAuthorization requests permission for notifications. -func (ns *NotificationService) RequestUserNotificationAuthorization() (bool, error) { +func (ns *Service) RequestUserNotificationAuthorization() (bool, error) { if !CheckBundleIdentifier() { return false, fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") } @@ -79,7 +83,7 @@ func (ns *NotificationService) RequestUserNotificationAuthorization() (bool, err } // CheckNotificationAuthorization checks current permission status -func (ns *NotificationService) CheckNotificationAuthorization() (bool, error) { +func (ns *Service) CheckNotificationAuthorization() (bool, error) { if !CheckBundleIdentifier() { return false, fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") } @@ -87,7 +91,7 @@ func (ns *NotificationService) CheckNotificationAuthorization() (bool, error) { } // SendNotification sends a notification with the given identifier, title, subtitle, and body. -func (ns *NotificationService) SendNotification(identifier, title, subtitle, body string) error { +func (ns *Service) SendNotification(identifier, title, subtitle, body string) error { if !CheckBundleIdentifier() { return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") } @@ -105,7 +109,7 @@ func (ns *NotificationService) SendNotification(identifier, title, subtitle, bod } // SendNotificationWithActions sends a notification with the specified actions -func (ns *NotificationService) SendNotificationWithActions(options NotificationOptions) error { +func (ns *Service) SendNotificationWithActions(options NotificationOptions) error { if !CheckBundleIdentifier() { return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") } @@ -134,7 +138,7 @@ func (ns *NotificationService) SendNotificationWithActions(options NotificationO } // RegisterNotificationCategory registers a category with actions and optional reply field -func (ns *NotificationService) RegisterNotificationCategory(category NotificationCategory) error { +func (ns *Service) RegisterNotificationCategory(category NotificationCategory) error { if !CheckBundleIdentifier() { return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") } @@ -162,7 +166,7 @@ func (ns *NotificationService) RegisterNotificationCategory(category Notificatio } // RemoveAllPendingNotifications removes all pending notifications -func (ns *NotificationService) RemoveAllPendingNotifications() error { +func (ns *Service) RemoveAllPendingNotifications() error { if !CheckBundleIdentifier() { return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") } @@ -171,7 +175,7 @@ func (ns *NotificationService) RemoveAllPendingNotifications() error { } // RemovePendingNotification removes a specific pending notification -func (ns *NotificationService) RemovePendingNotification(identifier string) error { +func (ns *Service) RemovePendingNotification(identifier string) error { if !CheckBundleIdentifier() { return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") } @@ -181,7 +185,7 @@ func (ns *NotificationService) RemovePendingNotification(identifier string) erro return nil } -func (ns *NotificationService) RemoveAllDeliveredNotifications() error { +func (ns *Service) RemoveAllDeliveredNotifications() error { if !CheckBundleIdentifier() { return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") } @@ -189,7 +193,7 @@ func (ns *NotificationService) RemoveAllDeliveredNotifications() error { return nil } -func (ns *NotificationService) RemoveDeliveredNotification(identifier string) error { +func (ns *Service) RemoveDeliveredNotification(identifier string) error { if !CheckBundleIdentifier() { return fmt.Errorf("Notifications require a bundled application with a unique bundle identifier") } diff --git a/v3/pkg/application/notifications_darwin.h b/v3/pkg/services/notifications/notifications_darwin.h similarity index 100% rename from v3/pkg/application/notifications_darwin.h rename to v3/pkg/services/notifications/notifications_darwin.h diff --git a/v3/pkg/application/notifications_darwin.m b/v3/pkg/services/notifications/notifications_darwin.m similarity index 99% rename from v3/pkg/application/notifications_darwin.m rename to v3/pkg/services/notifications/notifications_darwin.m index 7c0a1cade..f4e9b1404 100644 --- a/v3/pkg/application/notifications_darwin.m +++ b/v3/pkg/services/notifications/notifications_darwin.m @@ -1,7 +1,7 @@ #import "notifications_darwin.h" #import #import -#import "../events/events_darwin.h" +#import "../../events/events_darwin.h" extern bool hasListeners(unsigned int); extern void processApplicationEvent(unsigned int, void* data);