feat: keep Verstak running in the system tray
This commit is contained in:
@@ -42,6 +42,9 @@ var emitFrontendEvent = runtime.EventsEmit
|
||||
var initializeNativeNotifications = runtime.InitializeNotifications
|
||||
var cleanupNativeNotifications = runtime.CleanupNotifications
|
||||
var sendNativeNotification = runtime.SendNotification
|
||||
var hideNativeWindow = runtime.WindowHide
|
||||
var showNativeWindow = runtime.WindowShow
|
||||
var quitNativeApplication = runtime.Quit
|
||||
|
||||
type notificationService interface {
|
||||
Replace(pluginID string, requests []notifications.Request) error
|
||||
@@ -96,6 +99,7 @@ type App struct {
|
||||
activityEvents map[string]bool
|
||||
browserInboxEvents map[string]bool
|
||||
browserInboxEnabled atomic.Bool
|
||||
allowQuit atomic.Bool
|
||||
}
|
||||
|
||||
// SetNotificationService attaches the core-owned plugin notification scheduler.
|
||||
@@ -217,6 +221,34 @@ func (a *App) Shutdown(ctx context.Context) {
|
||||
cleanupNativeNotifications(ctx)
|
||||
}
|
||||
|
||||
// BeforeClose hides the primary window until the user explicitly quits from the tray.
|
||||
func (a *App) BeforeClose(ctx context.Context) bool {
|
||||
if a.allowQuit.Load() {
|
||||
return false
|
||||
}
|
||||
hideNativeWindow(ctx)
|
||||
return true
|
||||
}
|
||||
|
||||
// ShowWindow brings the primary window back from the tray.
|
||||
func (a *App) ShowWindow() {
|
||||
if a == nil || a.ctx == nil {
|
||||
return
|
||||
}
|
||||
showNativeWindow(a.ctx)
|
||||
}
|
||||
|
||||
// Quit allows the close event and ends the application process.
|
||||
func (a *App) Quit() {
|
||||
if a == nil {
|
||||
return
|
||||
}
|
||||
a.allowQuit.Store(true)
|
||||
if a.ctx != nil {
|
||||
quitNativeApplication(a.ctx)
|
||||
}
|
||||
}
|
||||
|
||||
// NativeNotificationSender delivers scheduler items through the Wails runtime.
|
||||
type NativeNotificationSender struct{}
|
||||
|
||||
|
||||
@@ -306,6 +306,55 @@ func TestNativeNotificationSenderUsesStablePluginScopedID(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBeforeCloseHidesWindowUntilUserChoosesQuit(t *testing.T) {
|
||||
oldHide := hideNativeWindow
|
||||
defer func() { hideNativeWindow = oldHide }()
|
||||
|
||||
hideCalls := 0
|
||||
hideNativeWindow = func(context.Context) { hideCalls++ }
|
||||
app := &App{}
|
||||
|
||||
if prevent := app.BeforeClose(context.Background()); !prevent {
|
||||
t.Fatal("BeforeClose() = false, want true while tray mode is active")
|
||||
}
|
||||
if hideCalls != 1 {
|
||||
t.Fatalf("hide calls = %d, want 1", hideCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrayQuitAllowsWindowCloseAndQuitsApplication(t *testing.T) {
|
||||
oldQuit := quitNativeApplication
|
||||
defer func() { quitNativeApplication = oldQuit }()
|
||||
|
||||
quitCalls := 0
|
||||
quitNativeApplication = func(context.Context) { quitCalls++ }
|
||||
app := &App{ctx: context.Background()}
|
||||
|
||||
app.Quit()
|
||||
|
||||
if quitCalls != 1 {
|
||||
t.Fatalf("quit calls = %d, want 1", quitCalls)
|
||||
}
|
||||
if prevent := app.BeforeClose(context.Background()); prevent {
|
||||
t.Fatal("BeforeClose() = true after Quit(), want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShowWindowUsesWailsContext(t *testing.T) {
|
||||
oldShow := showNativeWindow
|
||||
defer func() { showNativeWindow = oldShow }()
|
||||
|
||||
showCalls := 0
|
||||
showNativeWindow = func(context.Context) { showCalls++ }
|
||||
app := &App{ctx: context.Background()}
|
||||
|
||||
app.ShowWindow()
|
||||
|
||||
if showCalls != 1 {
|
||||
t.Fatalf("show calls = %d, want 1", showCalls)
|
||||
}
|
||||
}
|
||||
|
||||
// TestGetPluginFrontendInfo_KnownPluginWithFrontend verifies that
|
||||
// GetPluginFrontendInfo returns correct metadata for a plugin with a frontend.
|
||||
func TestGetPluginFrontendInfo_KnownPluginWithFrontend(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user