mirror of
https://github.com/konyshe/GoodLink.git
synced 2026-09-01 14:51:48 +08:00
286 lines
8.9 KiB
Go
286 lines
8.9 KiB
Go
//go:build windows
|
|
|
|
package ui2
|
|
|
|
import (
|
|
"encoding/json"
|
|
"go2"
|
|
"image/color"
|
|
"log"
|
|
|
|
"goodlink/config"
|
|
|
|
_ "embed"
|
|
_ "net/http/pprof"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/canvas"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/theme"
|
|
"fyne.io/fyne/v2/widget"
|
|
"github.com/atotto/clipboard"
|
|
)
|
|
|
|
// entryWrapper 包装 Entry 以实现 uiComponent 接口
|
|
type entryWrapper struct {
|
|
entry *widget.Entry
|
|
}
|
|
|
|
func (e *entryWrapper) Enable() { e.entry.Enable() }
|
|
func (e *entryWrapper) Disable() { e.entry.Disable() }
|
|
|
|
// buttonWrapper 包装 Button 以实现 uiComponent 接口
|
|
type buttonWrapper struct {
|
|
btn *widget.Button
|
|
}
|
|
|
|
func (b *buttonWrapper) Enable() { b.btn.Enable() }
|
|
func (b *buttonWrapper) Disable() { b.btn.Disable() }
|
|
|
|
var (
|
|
m_work_type string
|
|
m_btn_local *widget.Button
|
|
m_btn_remote *widget.Button
|
|
m_validated_key *widget.Entry
|
|
m_button_key_create *widget.Button
|
|
m_button_key_paste *widget.Button
|
|
m_btn_local_bg *canvas.Rectangle // 本地端按钮高亮背景
|
|
m_btn_remote_bg *canvas.Rectangle // 远程端按钮高亮背景
|
|
m_btn_local_border *canvas.Rectangle // 本地端按钮边框容器
|
|
m_btn_remote_border *canvas.Rectangle // 远程端按钮边框容器
|
|
)
|
|
|
|
const (
|
|
M_APP_TITLE = "GoodLink"
|
|
workTypeLocal = "Local"
|
|
workTypeRemote = "Remote"
|
|
)
|
|
|
|
// UI样式常量
|
|
var (
|
|
// 统一的背景颜色
|
|
bgColorPrimary = color.NRGBA{R: 45, G: 45, B: 55, A: 255} // 主要背景
|
|
bgColorSecondary = color.NRGBA{R: 40, G: 40, B: 50, A: 255} // 次要背景
|
|
bgColorCard = color.NRGBA{R: 50, G: 50, B: 60, A: 255} // 卡片背景
|
|
separatorColor = color.NRGBA{R: 100, G: 100, B: 100, A: 80} // 分隔线颜色
|
|
highlightColor = color.NRGBA{R: 0, G: 120, B: 255, A: 255} // 选中按钮高亮颜色(完全不透明,更亮)
|
|
highlightBorderColor = color.NRGBA{R: 0, G: 180, B: 255, A: 255} // 高亮边框颜色
|
|
// 统一的圆角半径
|
|
cornerRadius = float32(8)
|
|
// 统一的间距
|
|
paddingSize = float32(12)
|
|
)
|
|
|
|
// updateButtonHighlight 更新单个按钮的高亮状态
|
|
func updateButtonHighlight(btn *widget.Button, bg *canvas.Rectangle, border *canvas.Rectangle, isHighlighted bool) {
|
|
if isHighlighted {
|
|
btn.Importance = widget.HighImportance
|
|
bg.FillColor = highlightColor
|
|
border.StrokeColor = highlightBorderColor
|
|
border.StrokeWidth = 3
|
|
border.FillColor = color.Transparent
|
|
} else {
|
|
btn.Importance = widget.MediumImportance
|
|
bg.FillColor = color.Transparent
|
|
border.StrokeColor = color.Transparent
|
|
border.StrokeWidth = 0
|
|
border.FillColor = color.Transparent
|
|
}
|
|
btn.Refresh()
|
|
bg.Refresh()
|
|
border.Refresh()
|
|
}
|
|
|
|
// 更新工作模式按钮样式
|
|
func updateWorkTypeButtons(selected string) {
|
|
m_work_type = selected
|
|
isLocal := selected == workTypeLocal
|
|
|
|
updateButtonHighlight(m_btn_local, m_btn_local_bg, m_btn_local_border, isLocal)
|
|
updateButtonHighlight(m_btn_remote, m_btn_remote_bg, m_btn_remote_border, !isLocal)
|
|
}
|
|
|
|
// 获取当前工作类型
|
|
func GetWorkType() string {
|
|
return m_work_type
|
|
}
|
|
|
|
// createButtonWithHighlight 创建带高亮效果的按钮容器
|
|
func createButtonWithHighlight(btn *widget.Button, bg *canvas.Rectangle, border *canvas.Rectangle) *fyne.Container {
|
|
bg.CornerRadius = cornerRadius
|
|
border.CornerRadius = cornerRadius
|
|
|
|
buttonInner := container.NewStack(bg, btn)
|
|
buttonWithPadding := container.NewPadded(buttonInner)
|
|
return container.NewStack(border, buttonWithPadding)
|
|
}
|
|
|
|
// 创建工作模式选择器
|
|
func createWorkTypeSelector(configInfo *config.ConfigInfo) fyne.CanvasObject {
|
|
// 创建本地端按钮
|
|
m_btn_local = widget.NewButtonWithIcon(" Local端 ", theme.ComputerIcon(), nil)
|
|
|
|
// 创建远程端按钮
|
|
m_btn_remote = widget.NewButtonWithIcon(" Remote端 ", theme.StorageIcon(), nil)
|
|
|
|
// 创建按钮高亮背景
|
|
m_btn_local_bg = canvas.NewRectangle(color.Transparent)
|
|
m_btn_remote_bg = canvas.NewRectangle(color.Transparent)
|
|
|
|
// 创建外层边框容器(用于更明显的高亮显示)
|
|
m_btn_local_border = canvas.NewRectangle(color.Transparent)
|
|
m_btn_remote_border = canvas.NewRectangle(color.Transparent)
|
|
|
|
// 创建带高亮的按钮容器
|
|
localButtonContainer := createButtonWithHighlight(m_btn_local, m_btn_local_bg, m_btn_local_border)
|
|
remoteButtonContainer := createButtonWithHighlight(m_btn_remote, m_btn_remote_bg, m_btn_remote_border)
|
|
|
|
// 根据配置设置初始状态
|
|
if configInfo.WorkType == "" {
|
|
configInfo.WorkType = workTypeLocal
|
|
}
|
|
updateWorkTypeButtons(configInfo.WorkType)
|
|
|
|
// 创建分隔线
|
|
separator := canvas.NewRectangle(separatorColor)
|
|
separator.SetMinSize(fyne.NewSize(2, 30))
|
|
|
|
// 创建标签
|
|
label := widget.NewRichTextFromMarkdown("**工作端侧**: ")
|
|
|
|
// 组合按钮和分隔线
|
|
buttonGroup := container.NewHBox(
|
|
localButtonContainer,
|
|
separator,
|
|
remoteButtonContainer,
|
|
)
|
|
|
|
return container.NewBorder(nil, nil, label, nil, buttonGroup)
|
|
}
|
|
|
|
// 创建连接密钥输入区域
|
|
func createKeyInputSection(configInfo *config.ConfigInfo) fyne.CanvasObject {
|
|
m_validated_key = widget.NewEntry()
|
|
m_validated_key.SetPlaceHolder("自定义16-24字节长度")
|
|
if len(configInfo.TunKey) > 0 {
|
|
m_validated_key.SetText(configInfo.TunKey)
|
|
}
|
|
|
|
// 创建密钥标签和图标
|
|
keyLabel := widget.NewRichTextFromMarkdown("**连接密钥**: ")
|
|
|
|
// 创建输入框容器,将标签和输入框放在同一行
|
|
keyInputContainer := container.NewBorder(nil, nil, keyLabel, nil, m_validated_key)
|
|
|
|
return keyInputContainer
|
|
}
|
|
|
|
// 创建密钥操作按钮组
|
|
func createKeyButtons() fyne.CanvasObject {
|
|
m_button_key_create = widget.NewButtonWithIcon("生成密钥", theme.ContentAddIcon(), func() {
|
|
m_validated_key.SetText(string(go2.RandomBytes(24)))
|
|
})
|
|
|
|
key_copy_button := widget.NewButtonWithIcon("复制密钥", theme.ContentCopyIcon(), func() {
|
|
clipboard.WriteAll(m_validated_key.Text)
|
|
})
|
|
|
|
m_button_key_paste = widget.NewButtonWithIcon("粘贴密钥", theme.ContentPasteIcon(), func() {
|
|
if s, err := clipboard.ReadAll(); err == nil {
|
|
m_validated_key.SetText(s)
|
|
}
|
|
})
|
|
|
|
// 统一按钮样式
|
|
m_button_key_create.Importance = widget.MediumImportance
|
|
key_copy_button.Importance = widget.MediumImportance
|
|
m_button_key_paste.Importance = widget.MediumImportance
|
|
|
|
// 创建按钮容器,使用网格布局
|
|
buttonGrid := container.NewGridWithColumns(3, m_button_key_create, key_copy_button, m_button_key_paste)
|
|
|
|
return buttonGrid
|
|
}
|
|
|
|
func GetMainUI(myWindow *fyne.Window) *fyne.Container {
|
|
var configInfo config.ConfigInfo
|
|
json.Unmarshal(go2.FileReadAll("goodlink.json"), &configInfo)
|
|
log.Println(configInfo)
|
|
|
|
// 如果密钥为空,自动生成密钥
|
|
if len(configInfo.TunKey) == 0 {
|
|
configInfo.TunKey = string(go2.RandomBytes(24))
|
|
log.Println("自动生成密钥:", configInfo.TunKey)
|
|
}
|
|
|
|
// 创建各个UI组件
|
|
workTypeSelector := createWorkTypeSelector(&configInfo)
|
|
keyInputSection := createKeyInputSection(&configInfo)
|
|
keyButtons := createKeyButtons()
|
|
|
|
// 设置需要控制的UI组件列表(必须在所有组件创建后设置)
|
|
setUIComponents([]uiComponent{
|
|
&entryWrapper{entry: m_validated_key},
|
|
&buttonWrapper{btn: m_button_key_create},
|
|
&buttonWrapper{btn: m_button_key_paste},
|
|
&buttonWrapper{btn: m_btn_local},
|
|
&buttonWrapper{btn: m_btn_remote},
|
|
})
|
|
|
|
m_stats_start_button = 0
|
|
m_activity_start_button = widget.NewActivity()
|
|
m_button_start = widget.NewButtonWithIcon("点击启动", theme.MediaPlayIcon(), start_button_click)
|
|
m_button_start.Importance = widget.HighImportance
|
|
|
|
// 创建启动按钮容器
|
|
startButtonContainer := container.NewStack(m_button_start, m_activity_start_button)
|
|
|
|
// 创建配置区域容器(根据工作模式动态显示)
|
|
configContainer := container.NewVBox()
|
|
|
|
// 根据工作模式显示对应的配置
|
|
updateConfigDisplay := func() {
|
|
configContainer.RemoveAll()
|
|
configContainer.Refresh()
|
|
}
|
|
|
|
// 设置按钮点击事件
|
|
m_btn_local.OnTapped = func() {
|
|
updateWorkTypeButtons(workTypeLocal)
|
|
updateConfigDisplay()
|
|
}
|
|
m_btn_remote.OnTapped = func() {
|
|
updateWorkTypeButtons(workTypeRemote)
|
|
updateConfigDisplay()
|
|
}
|
|
|
|
// 初始显示
|
|
updateConfigDisplay()
|
|
|
|
// 创建顶部内容(工作模式选择器、密钥输入、配置区域)
|
|
topContent := container.NewVBox(
|
|
workTypeSelector,
|
|
keyInputSection,
|
|
keyButtons,
|
|
configContainer,
|
|
)
|
|
|
|
// 创建底部内容(启动按钮和页脚)
|
|
bottomContent := container.NewVBox(
|
|
startButtonContainer,
|
|
NewFooter(),
|
|
)
|
|
|
|
// 使用 Border 布局,让日志区域自适应占用剩余空间
|
|
mainContent := container.NewBorder(
|
|
topContent, // 顶部
|
|
bottomContent, // 底部
|
|
nil, // 左侧
|
|
nil, // 右侧
|
|
NewLogList(), // 中心(自适应区域)
|
|
)
|
|
|
|
// 添加最小外层padding,确保整体有合适的边距
|
|
return container.NewPadded(mainContent)
|
|
}
|