opencode-provider-switch/internal/desktop/app.go
2026-04-18 20:49:54 +08:00

168 lines
3.8 KiB
Go

package desktop
import (
"context"
"time"
"github.com/Apale7/opencode-provider-switch/internal/app"
)
// App is the desktop-shell composition root. Native shell integrations are kept
// out of internal/app so CLI and GUI can share the same workflows.
type App struct {
service *app.Service
bindings *Bindings
tray *Tray
notify *Notifier
auto *AutoStart
ctx context.Context
version string
}
func New(configPath string) *App {
svc := app.NewService(configPath)
instance := &App{service: svc}
instance.bindings = NewBindings(svc)
instance.tray = NewTray(svc)
instance.notify = NewNotifier(svc)
instance.auto = NewAutoStart(svc)
return instance
}
func (a *App) SetVersion(version string) {
a.version = version
}
func (a *App) Startup(ctx context.Context) {
a.ctx = ctx
a.tray.Attach(ctx)
a.notify.Attach(ctx)
a.auto.Attach(ctx)
_ = a.SyncDesktopPreferences(ctx)
}
func (a *App) BeforeClose(ctx context.Context) bool {
a.ctx = ctx
prevent, _ := a.tray.BeforeClose(ctx)
return prevent
}
func (a *App) Shutdown(ctx context.Context) {
a.ctx = ctx
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = a.service.StopProxy(shutdownCtx)
a.tray.Detach()
a.notify.Detach()
a.auto.Detach()
}
func (a *App) SyncDesktopPreferences(ctx context.Context) error {
prefs, err := a.bindings.GetDesktopPrefs(ctx)
if err != nil {
return err
}
if err := a.auto.Sync(ctx, prefs); err != nil {
return err
}
a.tray.Sync(ctx, prefs)
return nil
}
func (a *App) SaveDesktopPrefs(ctx context.Context, in app.DesktopPrefsInput) (app.DesktopPrefsView, error) {
prefs, err := a.bindings.SaveDesktopPrefs(ctx, in)
if err != nil {
return app.DesktopPrefsView{}, err
}
if err := a.auto.Sync(ctx, prefs); err != nil {
return app.DesktopPrefsView{}, err
}
a.tray.Sync(ctx, prefs)
return prefs, nil
}
func (a *App) SavePrefs(in app.DesktopPrefsInput) (app.DesktopPrefsView, error) {
return a.SaveDesktopPrefs(a.callContext(), in)
}
func (a *App) Meta() map[string]string {
return map[string]string{
"version": a.version,
"shell": a.shellName(),
}
}
func (a *App) Overview() (app.Overview, error) {
return a.bindings.GetOverview(a.callContext())
}
func (a *App) Providers() ([]app.ProviderView, error) {
return a.bindings.ListProviders(a.callContext())
}
func (a *App) Aliases() ([]app.AliasView, error) {
return a.bindings.ListAliases(a.callContext())
}
func (a *App) DoctorRun() (app.DoctorRunResult, error) {
report, err := a.bindings.RunDoctor(a.callContext())
return app.DoctorRunResult{Report: report, Error: errorString(err)}, nil
}
func (a *App) ProxyStatus() (app.ProxyStatusView, error) {
return a.bindings.GetProxyStatus(a.callContext())
}
func (a *App) StartProxy() (app.ProxyStatusView, error) {
return a.bindings.StartProxy(a.callContext())
}
func (a *App) StopProxy() (app.ProxyStatusView, error) {
ctx, cancel := context.WithTimeout(a.callContext(), 5*time.Second)
defer cancel()
return a.bindings.StopProxy(ctx)
}
func (a *App) DesktopPrefs() (app.DesktopPrefsView, error) {
return a.bindings.GetDesktopPrefs(a.callContext())
}
func (a *App) PreviewSync(in app.SyncInput) (app.SyncPreview, error) {
return a.bindings.PreviewOpenCodeSync(a.callContext(), in)
}
func (a *App) ApplySync(in app.SyncInput) (app.SyncResult, error) {
return a.bindings.SyncOpenCode(a.callContext(), in)
}
func (a *App) callContext() context.Context {
if a.ctx != nil {
return a.ctx
}
return context.Background()
}
func (a *App) shellName() string {
if a.ctx != nil {
return "wails"
}
return "browser"
}
func (a *App) Service() *app.Service {
return a.service
}
func (a *App) Bindings() *Bindings {
return a.bindings
}
func (a *App) Tray() *Tray {
return a.tray
}
func (a *App) AutoStart() *AutoStart {
return a.auto
}