更新代码
This commit is contained in:
1 parent
eda7e8bc96
commit
6ff632e0b0
19 files changed
+2033
-197
No files matched your search
+91
-5
@@ -25,6 +25,7 @@ import (
|
||||
"viewsagent/internal/capture"
|
||||
"viewsagent/internal/config"
|
||||
"viewsagent/internal/llm"
|
||||
"viewsagent/internal/logging"
|
||||
"viewsagent/internal/win32"
|
||||
)
|
||||
|
||||
@@ -44,10 +45,12 @@ type App struct {
|
||||
modelSel *widget.Select
|
||||
regionLbl *widget.Label
|
||||
statusLbl *widget.Label
|
||||
frameBtn *widget.Button
|
||||
settings *settingsWindow
|
||||
card *floatCard
|
||||
overlay *overlay
|
||||
regionFrm *regionFrame
|
||||
logs *logWindow
|
||||
hotkeyStop func()
|
||||
|
||||
// 流式文本合批,避免每个 delta 都触发一次布局
|
||||
@@ -62,10 +65,13 @@ type App struct {
|
||||
lastCardSync time.Time
|
||||
|
||||
quietModelSel bool
|
||||
// frameBtnShown 记录取景框按钮当前的图标状态,避免重复刷新。
|
||||
frameBtnShown bool
|
||||
}
|
||||
|
||||
// Run 启动整个桌面应用。
|
||||
func Run() error {
|
||||
// Run 启动整个桌面应用。logs 是程序自己的日志缓冲,
|
||||
// 界面上的「日志」按钮直接读它展示。
|
||||
func Run(logs *logging.Buffer) error {
|
||||
store, err := config.NewStore()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -79,7 +85,11 @@ func Run() error {
|
||||
eng := agent.New(cfg, store)
|
||||
|
||||
a := &App{fyne: fa, eng: eng}
|
||||
a.logs = newLogWindow(fa, logs, store.Dir())
|
||||
a.build()
|
||||
// 取景框上的「确定 / 取消」直接改监视区域。
|
||||
a.regionFrm.onApply = a.onFrameApply
|
||||
a.regionFrm.onCancel = a.onFrameCancel
|
||||
eng.SetSink(a)
|
||||
a.startHotkeys()
|
||||
a.maybeAutoShot()
|
||||
@@ -88,6 +98,9 @@ func Run() error {
|
||||
if a.hotkeyStop != nil {
|
||||
a.hotkeyStop()
|
||||
}
|
||||
a.logs.close()
|
||||
// 取景框是原生窗口,不随 Fyne 窗口一起消失,
|
||||
// 必须在这里显式销毁,否则屏幕上会留下一个关不掉的红色线框。
|
||||
a.regionFrm.close()
|
||||
eng.Close()
|
||||
}()
|
||||
@@ -159,6 +172,10 @@ func (a *App) build() {
|
||||
a.win = a.fyne.NewWindow(mainTitle)
|
||||
a.win.Resize(fyne.NewSize(520, 780))
|
||||
a.win.CenterOnScreen()
|
||||
// 主窗体是 master:点它的关闭按钮就直接退出整个程序。
|
||||
// 否则 Fyne 只会在最后一个窗口关闭时才退出,卡片/设置/日志窗口
|
||||
// 还活着,程序会变成后台僵尸,取景框的红色线框也留在屏幕上。
|
||||
a.win.SetMaster()
|
||||
|
||||
a.chat = newChatView()
|
||||
a.card = newFloatCard(a.fyne)
|
||||
@@ -175,12 +192,14 @@ func (a *App) build() {
|
||||
|
||||
cardBtn := widget.NewButtonWithIcon("", theme.InfoIcon(), a.toggleCard)
|
||||
cardBtn.Importance = widget.LowImportance
|
||||
logBtn := widget.NewButtonWithIcon("", theme.DocumentIcon(), a.showLogs)
|
||||
logBtn.Importance = widget.LowImportance
|
||||
settingsBtn := widget.NewButtonWithIcon("", theme.SettingsIcon(), a.openSettings)
|
||||
settingsBtn.Importance = widget.LowImportance
|
||||
|
||||
toolbar := container.NewHBox(
|
||||
widget.NewLabel("接入点"), a.modelSel,
|
||||
layout.NewSpacer(), cardBtn, settingsBtn,
|
||||
layout.NewSpacer(), cardBtn, logBtn, settingsBtn,
|
||||
)
|
||||
|
||||
a.regionLbl = widget.NewLabel("未框选区域")
|
||||
@@ -188,10 +207,12 @@ func (a *App) build() {
|
||||
selectBtn := widget.NewButtonWithIcon("框选", theme.VisibilityOffIcon(), a.startSelection)
|
||||
previewBtn := widget.NewButtonWithIcon("预览", theme.SearchIcon(), a.showPreview)
|
||||
previewBtn.Importance = widget.LowImportance
|
||||
a.frameBtn = widget.NewButtonWithIcon("取景框", theme.VisibilityIcon(), a.toggleFrame)
|
||||
a.frameBtn.Importance = widget.LowImportance
|
||||
a.watchBtn = widget.NewButtonWithIcon("开始监听", theme.MediaPlayIcon(), a.toggleWatch)
|
||||
a.watchBtn.Importance = widget.HighImportance
|
||||
|
||||
regionRow := container.NewHBox(a.regionLbl, layout.NewSpacer(), previewBtn, selectBtn, a.watchBtn)
|
||||
regionRow := container.NewHBox(a.regionLbl, layout.NewSpacer(), previewBtn, selectBtn, a.frameBtn, a.watchBtn)
|
||||
|
||||
a.entry = widget.NewMultiLineEntry()
|
||||
a.entry.SetPlaceHolder("输入你的要求,例如:请帮我做练习题,实时给出答案")
|
||||
@@ -289,6 +310,61 @@ func (a *App) openSettings() {
|
||||
a.settings.show()
|
||||
}
|
||||
|
||||
// showLogs 打开运行日志窗口。
|
||||
func (a *App) showLogs() {
|
||||
if a.logs == nil {
|
||||
return
|
||||
}
|
||||
a.logs.show()
|
||||
}
|
||||
|
||||
// toggleFrame 显示或隐藏屏幕上的取景框。
|
||||
func (a *App) toggleFrame() {
|
||||
if a.regionFrm == nil {
|
||||
return
|
||||
}
|
||||
if a.regionFrm.toggle() {
|
||||
a.chat.addNotice("已显示取景框:拖动边框可调整范围,右上角有确定/取消")
|
||||
} else {
|
||||
a.chat.addNotice("已隐藏取景框")
|
||||
}
|
||||
a.updateFrameBtn()
|
||||
}
|
||||
|
||||
// updateFrameBtn 同步取景框按钮的图标与可用状态。
|
||||
func (a *App) updateFrameBtn() {
|
||||
if a.frameBtn == nil {
|
||||
return
|
||||
}
|
||||
visible := a.regionFrm != nil && a.regionFrm.visible()
|
||||
if visible == a.frameBtnShown {
|
||||
return
|
||||
}
|
||||
a.frameBtnShown = visible
|
||||
if visible {
|
||||
a.frameBtn.SetIcon(theme.VisibilityIcon())
|
||||
} else {
|
||||
a.frameBtn.SetIcon(theme.VisibilityOffIcon())
|
||||
}
|
||||
}
|
||||
|
||||
// onFrameApply 取景框上点了确定:把拖出来的范围应用成监视区域。
|
||||
func (a *App) onFrameApply(r capture.Region) {
|
||||
if err := a.eng.SetRegion(r); err != nil {
|
||||
fyne.Do(func() { a.chat.addNotice(err.Error()) })
|
||||
return
|
||||
}
|
||||
fyne.Do(func() { a.chat.addNotice(fmt.Sprintf("已应用监视区域 %s", r)) })
|
||||
}
|
||||
|
||||
// onFrameCancel 取景框上点了取消:红框已经隐藏,这里只提示一句。
|
||||
func (a *App) onFrameCancel() {
|
||||
fyne.Do(func() {
|
||||
a.chat.addNotice("已取消取景框调整,监视区域保持不变")
|
||||
a.updateFrameBtn()
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) clearChat() {
|
||||
a.eng.ResetHistory()
|
||||
a.chat.clear()
|
||||
@@ -358,7 +434,8 @@ func (a *App) startSelection() {
|
||||
return
|
||||
}
|
||||
vd := win32.VirtualScreen()
|
||||
a.overlay = newOverlay(a.fyne, shot, vd, a.onRegionSelected, a.onRegionCancel)
|
||||
// 把上一次的选区带进去,打开就能直接移动或调整边界。
|
||||
a.overlay = newOverlay(a.fyne, shot, vd, a.eng.Region(), a.onRegionSelected, a.onRegionCancel)
|
||||
a.overlay.show()
|
||||
}
|
||||
|
||||
@@ -372,6 +449,8 @@ func (a *App) onRegionSelected(r capture.Region) {
|
||||
}
|
||||
a.card.setRegion(r)
|
||||
a.regionFrm.resume(r)
|
||||
// 重新框选后把红框显示出来(之前点过取消的话,这里恢复)。
|
||||
a.regionFrm.show()
|
||||
a.chat.addNotice(fmt.Sprintf("已框选监视区域 %s", r))
|
||||
}
|
||||
|
||||
@@ -541,12 +620,19 @@ func (a *App) applyState(st agent.State) {
|
||||
|
||||
if st.Region.Valid() {
|
||||
a.regionLbl.SetText(fmt.Sprintf("区域 %d × %d", st.Region.W, st.Region.H))
|
||||
if a.frameBtn != nil {
|
||||
a.frameBtn.Enable()
|
||||
}
|
||||
} else {
|
||||
a.regionLbl.SetText("未框选区域")
|
||||
if a.frameBtn != nil {
|
||||
a.frameBtn.Disable()
|
||||
}
|
||||
}
|
||||
a.card.setRegion(st.Region)
|
||||
// 屏幕上的红框跟着选区走,始终提示当前盯的是哪一块。
|
||||
a.regionFrm.apply(st.Region)
|
||||
a.updateFrameBtn()
|
||||
|
||||
if st.Busy {
|
||||
a.sendBtn.Disable()
|
||||
|
||||
Reference in new issue
Block a user