Спеца 12.12: интерфейс + Nil + FormatRole в internal/ui/chat_panel.go, Fyne-реализация в internal/ui/desktop/chat_panel.go (транскрипт + композитор). Окно как chat.Channel рендерит Send/Ask/историю через Append; state_panel не трогаем.
87 lines
2.6 KiB
Go
87 lines
2.6 KiB
Go
//go:build cgo
|
|
|
|
package desktop
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/container"
|
|
"fyne.io/fyne/v2/widget"
|
|
|
|
"github.com/kamelion/ratatoskr-go/internal/ui"
|
|
)
|
|
|
|
// chatLimit — обрезка буфера транскрипта диалога (спец 12.12).
|
|
const chatLimit = 200_000
|
|
|
|
// ChatPanel — Fyne-реализация ui.ChatPanel (спец 12.8, 12.12): транскрипт
|
|
// диалога + композитор (поле ввода и кнопки команд).
|
|
type ChatPanel struct {
|
|
convLbl *widget.Label
|
|
input *widget.Entry
|
|
commands *ui.Commands
|
|
}
|
|
|
|
// NewChatPanel создаёт ChatPanel.
|
|
func NewChatPanel() *ChatPanel {
|
|
p := &ChatPanel{}
|
|
p.convLbl = widget.NewLabel("Выберите задачу.")
|
|
p.convLbl.Wrapping = fyne.TextWrapWord
|
|
p.input = widget.NewEntry()
|
|
p.input.SetPlaceHolder("Сообщение… (Enter — отправить)")
|
|
return p
|
|
}
|
|
|
|
// Transcript возвращает виджет транскрипта (Scroll) для встраивания в окно.
|
|
func (p *ChatPanel) Transcript() fyne.CanvasObject {
|
|
return container.NewScroll(p.convLbl)
|
|
}
|
|
|
|
// Composer возвращает виджет композитора (ввод + кнопки команд).
|
|
func (p *ChatPanel) Composer() fyne.CanvasObject {
|
|
cmdBar := container.NewHBox(
|
|
widget.NewButton("Новая", func() { if p.commands != nil { p.commands.Start() } }),
|
|
widget.NewButton("Создавай", func() { if p.commands != nil { p.commands.Approve() } }),
|
|
widget.NewButton("Пропустить", func() { if p.commands != nil { p.commands.Skip() } }),
|
|
widget.NewButton("Отмена", func() { if p.commands != nil { p.commands.Cancel() } }),
|
|
)
|
|
return container.NewBorder(nil, nil, cmdBar, p.input, nil)
|
|
}
|
|
|
|
// SetTranscript заменяет содержимое диалога (спец 12.12).
|
|
func (p *ChatPanel) SetTranscript(text string) {
|
|
p.convLbl.SetText(text)
|
|
}
|
|
|
|
// Append добавляет строку в диалог (буфер ограничен).
|
|
func (p *ChatPanel) Append(text string) {
|
|
s := p.convLbl.Text + text + "\n\n"
|
|
if len(s) > chatLimit {
|
|
s = s[len(s)-chatLimit:]
|
|
}
|
|
p.convLbl.SetText(s)
|
|
}
|
|
|
|
// Clear очищает диалог.
|
|
func (p *ChatPanel) Clear() {
|
|
p.convLbl.SetText("")
|
|
}
|
|
|
|
// SetCommands подключает команды к композитору.
|
|
func (p *ChatPanel) SetCommands(c *ui.Commands) {
|
|
p.commands = c
|
|
p.input.OnSubmitted = func(s string) {
|
|
s = strings.TrimSpace(s)
|
|
if s == "" {
|
|
return
|
|
}
|
|
p.input.SetText("")
|
|
if c != nil {
|
|
c.SendText(s)
|
|
}
|
|
}
|
|
}
|
|
|
|
// compile-time проверка реализации контракта.
|
|
var _ ui.ChatPanel = (*ChatPanel)(nil) |