From 8fc72e87e4e3d46bf200d0bd2215359c001d8e77 Mon Sep 17 00:00:00 2001 From: apale7 <1092377056@qq.com> Date: Mon, 20 Apr 2026 02:36:54 +0800 Subject: [PATCH] fix(desktop): finish Windows shell polish Stabilize the tray icon and locale handling on Windows while aligning provider and alias management panels with the refreshed desktop branding. --- .../task.json | 45 +- frontend/assets.go | 53 ++ frontend/src/App.tsx | 526 +++++++++++------- frontend/src/api.ts | 12 + .../GitHub_Invertocat_Black_Clearspace.png | Bin 0 -> 5753 bytes frontend/src/assets/icon.svg | 61 ++ frontend/src/env.d.ts | 11 + frontend/src/i18n/locales/en.json | 29 + frontend/src/i18n/locales/zh-CN.json | 29 + frontend/src/styles.css | 470 +++++++++++++--- frontend/wailsjs/go/desktop/App.d.ts | 2 + frontend/wailsjs/go/desktop/App.js | 4 + go.mod | 10 +- go.sum | 28 +- internal/desktop/app.go | 9 + internal/desktop/assets/icon.ico | Bin 0 -> 208192 bytes internal/desktop/runtime_fallback.go | 5 + internal/desktop/runtime_wails.go | 11 + internal/desktop/tray_language.go | 36 ++ internal/desktop/tray_language_other.go | 7 + internal/desktop/tray_language_test.go | 47 ++ internal/desktop/tray_language_windows.go | 20 + internal/desktop/tray_wails.go | 146 ++++- internal/desktop/wails.go | 6 +- 24 files changed, 1249 insertions(+), 318 deletions(-) create mode 100644 frontend/src/assets/GitHub_Invertocat_Black_Clearspace.png create mode 100644 frontend/src/assets/icon.svg create mode 100644 internal/desktop/assets/icon.ico create mode 100644 internal/desktop/tray_language.go create mode 100644 internal/desktop/tray_language_other.go create mode 100644 internal/desktop/tray_language_test.go create mode 100644 internal/desktop/tray_language_windows.go diff --git a/.trellis/tasks/04-18-04-18-finish-windows-desktop/task.json b/.trellis/tasks/04-18-04-18-finish-windows-desktop/task.json index 2538ac4..1ea5ea0 100644 --- a/.trellis/tasks/04-18-04-18-finish-windows-desktop/task.json +++ b/.trellis/tasks/04-18-04-18-finish-windows-desktop/task.json @@ -3,19 +3,19 @@ "name": "04-18-finish-windows-desktop", "title": "Finish Windows desktop integration", "description": "", - "status": "planning", - "dev_type": null, - "scope": null, + "status": "completed", + "dev_type": "feature", + "scope": "desktop", "package": null, "priority": "P2", "creator": "OpenCode", "assignee": "OpenCode", "createdAt": "2026-04-18", - "completedAt": null, - "branch": null, + "completedAt": "2026-04-20", + "branch": "master", "base_branch": "master", "worktree_path": null, - "current_phase": 0, + "current_phase": 6, "next_action": [ { "phase": 1, @@ -47,7 +47,32 @@ "subtasks": [], "children": [], "parent": null, - "relatedFiles": [], - "notes": "", - "meta": {} -} \ No newline at end of file + "relatedFiles": [ + "build/windows/icon.ico", + "frontend/assets.go", + "frontend/src/App.tsx", + "frontend/src/api.ts", + "frontend/src/i18n/locales/en.json", + "frontend/src/i18n/locales/zh-CN.json", + "frontend/src/styles.css", + "internal/desktop/app.go", + "internal/desktop/runtime_wails.go", + "internal/desktop/tray_wails.go", + "internal/desktop/tray_language.go", + "internal/desktop/tray_language_windows.go", + "internal/desktop/wails.go" + ], + "notes": "Finished the Windows desktop integration pass. Reworked tray startup onto a stable systray event loop with icon embedding, click-to-open behavior, localized menu labels, and Windows system-language fallback. Replaced desktop/window branding assets, wired repository opening through the system browser, and refreshed the providers and aliases list/detail panels into a denser, product-style UI with updated i18n strings.", + "meta": { + "tests": [ + "npm run build", + "go test -tags desktop_wails ./internal/desktop/..." + ], + "desktopAreas": [ + "windows tray", + "window icon and branding", + "providers panel", + "aliases panel" + ] + } +} diff --git a/frontend/assets.go b/frontend/assets.go index aa767c3..4fffae6 100644 --- a/frontend/assets.go +++ b/frontend/assets.go @@ -2,12 +2,65 @@ package frontend import ( "embed" + "encoding/json" + "fmt" "io/fs" + "sync" ) //go:embed dist/* var assets embed.FS +//go:embed src/i18n/locales/*.json +var localeAssets embed.FS + +var ( + localeCache = map[string]map[string]any{} + localeCacheMu sync.RWMutex +) + func DistFS() (fs.FS, error) { return fs.Sub(assets, "dist") } + +func LocaleValue(language string, path ...string) (string, bool, error) { + locale, err := loadLocale(language) + if err != nil { + return "", false, err + } + var current any = locale + for _, key := range path { + next, ok := current.(map[string]any) + if !ok { + return "", false, nil + } + current, ok = next[key] + if !ok { + return "", false, nil + } + } + value, ok := current.(string) + return value, ok, nil +} + +func loadLocale(language string) (map[string]any, error) { + localeCacheMu.RLock() + if locale, ok := localeCache[language]; ok { + localeCacheMu.RUnlock() + return locale, nil + } + localeCacheMu.RUnlock() + + data, err := localeAssets.ReadFile(fmt.Sprintf("src/i18n/locales/%s.json", language)) + if err != nil { + return nil, err + } + var locale map[string]any + if err := json.Unmarshal(data, &locale); err != nil { + return nil, err + } + localeCacheMu.Lock() + localeCache[language] = locale + localeCacheMu.Unlock() + return locale, nil +} diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 21125d8..fe22835 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -20,6 +20,7 @@ import { saveDesktopPrefs, saveProxySettings, saveProvider, + openExternalURL, setAliasTargetState, setProviderState, startProxy, @@ -27,6 +28,7 @@ import { unbindAliasTarget, } from './api' import i18n, { resolveLanguagePreference } from './i18n' +import githubMark from './assets/GitHub_Invertocat_Black_Clearspace.png' import type { AliasTargetInput, AliasView, @@ -85,6 +87,7 @@ type ConfirmIntent = | { kind: 'unbind-target'; alias: string; provider: string; model: string } const tabs: TabKey[] = ['overview', 'providers', 'aliases', 'log', 'network', 'sync', 'settings'] +const GITHUB_REPOSITORY_URL = 'https://github.com/Apale7/opencode-provider-switch' const emptyPrefs: DesktopPrefsView = { launchAtLogin: false, @@ -1105,6 +1108,13 @@ export default function App() { : t('confirm.unbindTargetTitle') : '' + function openRepository() { + if (!GITHUB_REPOSITORY_URL) { + return + } + void openExternalURL(GITHUB_REPOSITORY_URL) + } + const confirmMessage = confirmIntent ? confirmIntent.kind === 'delete-provider' ? t('messages.confirmDeleteProvider', { id: confirmIntent.id }) @@ -1131,8 +1141,19 @@ export default function App() {