- 新增竞速拨号器(racedial.go):域名连接时并行解析所有A/AAAA记录, 同时对所有IP发起TCP连接,第一个成功的胜出,确保选择延迟最低的地址 - ServerProfile新增IPPreference字段(auto/v4/v6),支持用户指定IP版本偏好 - 填写服务器IP时跳过域名解析直接使用IP,顺序failover - 连接成功后状态栏显示「已连接 (域名 -> 实际IP)」 - DB迁移v6:server_profiles表添加ip_preference列 - WebSocket拨号与HTTP登录均使用竞速拨号器 - 补充中英文i18n翻译
84 lines
2.1 KiB
Go
84 lines
2.1 KiB
Go
package ui
|
|
|
|
import (
|
|
_ "embed"
|
|
"lmvpn/internal/i18n"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/driver/desktop"
|
|
)
|
|
|
|
//go:embed tray-icon.png
|
|
var trayIconBytes []byte
|
|
|
|
// setupTray configures the system tray menu (desktop only).
|
|
func (a *App) setupTray() {
|
|
deskApp, ok := a.fyneApp.(desktop.App)
|
|
if !ok {
|
|
return // not a desktop app, skip tray
|
|
}
|
|
|
|
// Language submenu — labels for English and 中文 are always shown in
|
|
// their native script so the user can recognise them regardless of
|
|
// the active language.
|
|
autoItem := fyne.NewMenuItem(i18n.T("TrayLanguageAuto"), func() {
|
|
a.changeLanguage(i18n.LangAuto)
|
|
})
|
|
enItem := fyne.NewMenuItem("English", func() {
|
|
a.changeLanguage(i18n.LangEn)
|
|
})
|
|
zhItem := fyne.NewMenuItem("中文", func() {
|
|
a.changeLanguage(i18n.LangZhHans)
|
|
})
|
|
|
|
// Mark the currently selected option.
|
|
switch {
|
|
case a.langSetting == "" || a.langSetting == i18n.LangAuto:
|
|
autoItem.Checked = true
|
|
case a.langSetting == i18n.LangEn:
|
|
enItem.Checked = true
|
|
case a.langSetting == i18n.LangZhHans:
|
|
zhItem.Checked = true
|
|
}
|
|
|
|
langItem := fyne.NewMenuItem(i18n.T("TrayLanguage"), nil)
|
|
langItem.ChildMenu = fyne.NewMenu(i18n.T("TrayLanguage"),
|
|
autoItem, enItem, zhItem,
|
|
)
|
|
|
|
connectItem := fyne.NewMenuItem(i18n.T("TrayConnect"), func() {
|
|
a.onConnect()
|
|
})
|
|
disconnectItem := fyne.NewMenuItem(i18n.T("TrayDisconnect"), func() {
|
|
a.onDisconnect()
|
|
})
|
|
if a.connectBtn != nil {
|
|
connectItem.Disabled = a.connectBtn.Disabled()
|
|
}
|
|
if a.disconnectBtn != nil {
|
|
disconnectItem.Disabled = a.disconnectBtn.Disabled()
|
|
}
|
|
|
|
menu := fyne.NewMenu(i18n.T("WindowTitle"),
|
|
fyne.NewMenuItem(i18n.T("TrayShowWindow"), func() {
|
|
a.windowHidden = false
|
|
activateApp()
|
|
showDockIcon()
|
|
a.window.Show()
|
|
a.window.RequestFocus()
|
|
}),
|
|
fyne.NewMenuItemSeparator(),
|
|
connectItem,
|
|
disconnectItem,
|
|
fyne.NewMenuItemSeparator(),
|
|
langItem,
|
|
fyne.NewMenuItemSeparator(),
|
|
fyne.NewMenuItem(i18n.T("TrayQuit"), func() {
|
|
a.quit()
|
|
}),
|
|
)
|
|
deskApp.SetSystemTrayMenu(menu)
|
|
trayIcon := fyne.NewStaticResource("tray-icon.png", trayIconBytes)
|
|
deskApp.SetSystemTrayIcon(trayIcon)
|
|
}
|