package bridge import ( "cursor/internal/buildinfo" "cursor/internal/client" "cursor/internal/updater" "fmt" "os" "os/exec" goruntime "runtime" "sync" "github.com/leaanthony/u" "github.com/wailsapp/wails/v3/pkg/application" "github.com/wailsapp/wails/v3/pkg/events" ) // modelEditorContext 保存当前模型编辑器窗口的初始化上下文。 type modelEditorContext struct { Index int `json:"index"` AdapterJSON string `json:"adapterJSON"` } // WindowService 定义了当前模块中的 WindowService 类型。 type WindowService struct { app *application.App updater *updater.Manager modelConfigWindow *application.WebviewWindow modelEditorWindow *application.WebviewWindow editorCtx *modelEditorContext mu sync.RWMutex } // NewWindowService 用于处理与 NewWindowService 相关的逻辑。 func NewWindowService() *WindowService { return &WindowService{} } // SetApp 用于处理与 SetApp 相关的逻辑。 func (s *WindowService) SetApp(app *application.App) { s.mu.Lock() defer s.mu.Unlock() s.app = app } // SetUpdater 关联更新管理器,供前端手动触发检查更新。 func (s *WindowService) SetUpdater(manager *updater.Manager) { s.mu.Lock() defer s.mu.Unlock() s.updater = manager } // GetAppVersion 返回当前应用版本号。 func (s *WindowService) GetAppVersion() string { return buildinfo.CurrentVersion() } // CheckForUpdates 触发一次手动检查更新。 func (s *WindowService) CheckForUpdates() { s.mu.RLock() manager := s.updater s.mu.RUnlock() if manager == nil { return } manager.CheckNow(true) } // InstallReadyUpdate 安装当前已下载完成的更新。 func (s *WindowService) InstallReadyUpdate() error { s.mu.RLock() manager := s.updater s.mu.RUnlock() if manager == nil { return fmt.Errorf("更新管理器未初始化") } return manager.InstallReadyUpdate() } // OpenConfigWindow 打开本地设置目录。 func (s *WindowService) OpenConfigWindow() { _ = os.MkdirAll(client.ResolveSettingsRootPath(), 0o755) openDirectory(client.ResolveSettingsRootPath()) } // OpenModelConfigWindow 打开模型配置独立窗口。如果窗口已存在则聚焦。 func (s *WindowService) OpenModelConfigWindow() { s.mu.Lock() defer s.mu.Unlock() if s.app == nil { return } if s.modelConfigWindow != nil { s.modelConfigWindow.Show() s.modelConfigWindow.Focus() return } win := s.app.Window.NewWithOptions(application.WebviewWindowOptions{ Title: "模型配置", Width: 980, Height: 700, MinWidth: 820, MinHeight: 560, DisableResize: false, Frameless: goruntime.GOOS == "windows", URL: "/#/model-config", Hidden: false, HideOnEscape: false, MinimiseButtonState: application.ButtonEnabled, MaximiseButtonState: application.ButtonEnabled, CloseButtonState: application.ButtonEnabled, BackgroundColour: application.RGBA{Red: 25, Green: 25, Blue: 25, Alpha: 255}, Mac: application.MacWindow{ Backdrop: application.MacBackdropLiquidGlass, DisableShadow: false, TitleBar: application.MacTitleBar{ AppearsTransparent: true, Hide: false, HideTitle: true, FullSizeContent: true, UseToolbar: false, HideToolbarSeparator: true, }, WebviewPreferences: application.MacWebviewPreferences{ FullscreenEnabled: u.True, TextInteractionEnabled: u.True, AllowsBackForwardNavigationGestures: u.False, }, }, Windows: application.WindowsWindow{ HiddenOnTaskbar: false, }, }) win.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) { s.mu.Lock() defer s.mu.Unlock() s.modelConfigWindow = nil }) s.modelConfigWindow = win } // OpenModelEditorWindow 打开模型编辑器独立窗口。 // index < 0 表示新增,>= 0 表示编辑对应索引的适配器。 // adapterJSON 为编辑器初始数据的 JSON 字符串。 func (s *WindowService) OpenModelEditorWindow(index int, adapterJSON string) { s.mu.Lock() defer s.mu.Unlock() if s.app == nil { return } s.editorCtx = &modelEditorContext{ Index: index, AdapterJSON: adapterJSON, } if s.modelEditorWindow != nil { s.modelEditorWindow.Show() s.modelEditorWindow.Focus() return } title := "新增模型配置" if index >= 0 { title = "编辑模型配置" } win := s.app.Window.NewWithOptions(application.WebviewWindowOptions{ Title: title, Width: 840, Height: 680, MinWidth: 740, MinHeight: 600, DisableResize: false, Frameless: goruntime.GOOS == "windows", URL: fmt.Sprintf("/#/model-editor?index=%d", index), Hidden: false, HideOnEscape: false, MinimiseButtonState: application.ButtonEnabled, MaximiseButtonState: application.ButtonHidden, CloseButtonState: application.ButtonEnabled, BackgroundColour: application.RGBA{Red: 25, Green: 25, Blue: 25, Alpha: 255}, Mac: application.MacWindow{ Backdrop: application.MacBackdropLiquidGlass, DisableShadow: false, TitleBar: application.MacTitleBar{ AppearsTransparent: true, Hide: false, HideTitle: true, FullSizeContent: true, UseToolbar: false, HideToolbarSeparator: true, }, WebviewPreferences: application.MacWebviewPreferences{ FullscreenEnabled: u.False, TextInteractionEnabled: u.True, AllowsBackForwardNavigationGestures: u.False, }, }, Windows: application.WindowsWindow{ HiddenOnTaskbar: false, }, }) win.RegisterHook(events.Common.WindowClosing, func(e *application.WindowEvent) { s.mu.Lock() defer s.mu.Unlock() s.modelEditorWindow = nil s.editorCtx = nil }) s.modelEditorWindow = win } // GetModelEditorContext 返回当前编辑器窗口的初始化上下文。 func (s *WindowService) GetModelEditorContext() map[string]any { s.mu.RLock() defer s.mu.RUnlock() if s.editorCtx == nil { return map[string]any{ "index": -1, "adapterJSON": "{}", } } return map[string]any{ "index": s.editorCtx.Index, "adapterJSON": s.editorCtx.AdapterJSON, } } // OpenHistoryWindow 用于处理与 OpenHistoryWindow 相关的逻辑。 func (s *WindowService) OpenHistoryWindow() { _ = os.MkdirAll(client.ResolveLogsRootPath(), 0o755) openDirectory(client.ResolveLogsRootPath()) } // openDirectory 用于处理与 openDirectory 相关的逻辑。 func openDirectory(path string) { if path == "" { return } switch goruntime.GOOS { case "darwin": _ = exec.Command("open", path).Start() case "windows": _ = exec.Command("explorer", path).Start() default: _ = exec.Command("xdg-open", path).Start() } }