Implement tray message fallback

This commit is contained in:
Snider 2026-04-15 14:22:41 +01:00
parent 07399bf260
commit 31dcf82331
3 changed files with 67 additions and 2 deletions

View file

@ -4,6 +4,8 @@ import (
"context"
core "dappco.re/go/core"
coreerr "dappco.re/go/core/log"
"forge.lthn.ai/core/gui/pkg/notification"
)
type Options struct{}
@ -41,7 +43,23 @@ func (s *Service) OnStartup(_ context.Context) core.Result {
})
s.Core().Action("systray.showMessage", func(_ context.Context, opts core.Options) core.Result {
t, _ := opts.Get("task").Value.(TaskShowMessage)
return core.Result{Value: nil, OK: true}.New(s.manager.ShowMessage(t.Title, t.Message))
if err := s.manager.ShowMessage(t.Title, t.Message); err == nil {
return core.Result{OK: true}
} else {
fallback := s.Core().Action("notification.send").Run(context.Background(), core.NewOptions(
core.Option{Key: "task", Value: notification.TaskSend{Options: notification.NotificationOptions{
Title: t.Title,
Message: t.Message,
}}},
))
if fallback.OK {
return core.Result{OK: true}
}
if fallbackErr, ok := fallback.Value.(error); ok {
return core.Result{Value: coreerr.E("systray.showMessage", "tray message failed and notification fallback failed", fallbackErr), OK: false}
}
return core.Result{Value: err, OK: false}
}
})
s.Core().Action("systray.showPanel", func(_ context.Context, _ core.Options) core.Result {
// Panel show — deferred (requires WindowHandle integration)

View file

@ -5,6 +5,7 @@ import (
"testing"
core "dappco.re/go/core"
"forge.lthn.ai/core/gui/pkg/notification"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -87,6 +88,51 @@ func TestTaskShowMessage_Good(t *testing.T) {
assert.Equal(t, "Up", mockTray.lastMessageBody)
}
type fallbackNotificationPlatform struct {
sent bool
opts notification.NotificationOptions
}
func (m *fallbackNotificationPlatform) Send(opts notification.NotificationOptions) error {
m.sent = true
m.opts = opts
return nil
}
func (m *fallbackNotificationPlatform) RequestPermission() (bool, error) { return true, nil }
func (m *fallbackNotificationPlatform) CheckPermission() (bool, error) { return true, nil }
func (m *fallbackNotificationPlatform) RevokePermission() error { return nil }
func (m *fallbackNotificationPlatform) Clear(id string) error { return nil }
type failingTrayPlatform struct{}
func (failingTrayPlatform) NewTray() PlatformTray { return &failingTray{} }
func (failingTrayPlatform) NewMenu() PlatformMenu { return &mockTrayMenu{} }
type failingTray struct{ mockTray }
func (t *failingTray) ShowMessage(title, message string) error {
return core.NewError("tray balloon unavailable")
}
func TestTaskShowMessage_FallbackToNotification_Good(t *testing.T) {
notifPlatform := &fallbackNotificationPlatform{}
c := core.New(
core.WithService(notification.Register(notifPlatform)),
core.WithService(Register(failingTrayPlatform{})),
core.WithServiceLock(),
)
require.True(t, c.ServiceStartup(context.Background(), nil).OK)
svc := core.MustServiceFor[*Service](c, "systray")
require.NoError(t, svc.manager.Setup("Test", "Test"))
r := taskRun(c, "systray.showMessage", TaskShowMessage{Title: "Core", Message: "Up"})
require.True(t, r.OK)
assert.True(t, notifPlatform.sent)
assert.Equal(t, "Core", notifPlatform.opts.Title)
assert.Equal(t, "Up", notifPlatform.opts.Message)
}
func TestQueryInfo_Good(t *testing.T) {
svc, c := newTestSystrayService(t)
require.NoError(t, svc.manager.Setup("Core", "Core"))

View file

@ -2,6 +2,7 @@
package systray
import (
coreerr "dappco.re/go/core/log"
"github.com/wailsapp/wails/v3/pkg/application"
)
@ -54,7 +55,7 @@ func (wt *wailsTray) AttachWindow(w WindowHandle) {
func (wt *wailsTray) ShowMessage(title, message string) error {
_ = title
_ = message
return nil
return coreerr.E("systray.wailsTray.ShowMessage", "tray balloon messages are not supported by this backend", nil)
}
// wailsTrayMenu wraps *application.Menu for the PlatformMenu interface.