refactor(ui): вынести панель «Список задач» (TaskListPanel) из монолита окна
Спеца 12.10: интерфейс + Nil + TaskTitle в internal/ui/task_list_panel.go, Fyne-реализация в internal/ui/desktop/task_list_panel.go. Состояние выбора живёт в окне; выбранная строка подсвечивается (Select/Unselect).
This commit is contained in:
@@ -10,7 +10,6 @@ import (
|
||||
"context"
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/app"
|
||||
@@ -21,7 +20,6 @@ import (
|
||||
"github.com/kamelion/ratatoskr-go/internal/chat"
|
||||
"github.com/kamelion/ratatoskr-go/internal/events"
|
||||
"github.com/kamelion/ratatoskr-go/internal/model"
|
||||
"github.com/kamelion/ratatoskr-go/internal/storage"
|
||||
"github.com/kamelion/ratatoskr-go/internal/ui"
|
||||
)
|
||||
|
||||
@@ -41,13 +39,11 @@ type Window struct {
|
||||
|
||||
handler chat.Handler
|
||||
|
||||
// состояние списка
|
||||
mu sync.Mutex // защищает tasks
|
||||
tasks []storage.Task
|
||||
// состояние выбора (живёт в окне, спец 12.10)
|
||||
selected int64
|
||||
|
||||
// виджеты
|
||||
list *widget.List
|
||||
taskList *TaskListPanel
|
||||
titleLbl *widget.Label
|
||||
statusLbl *widget.Label
|
||||
detailLbl *widget.Label
|
||||
@@ -103,31 +99,8 @@ func (w *Window) build() {
|
||||
w.stateLbl.Wrapping = fyne.TextWrapWord
|
||||
|
||||
// Список задач (слева)
|
||||
w.list = widget.NewList(
|
||||
func() int { w.mu.Lock(); defer w.mu.Unlock(); return len(w.tasks) },
|
||||
func() fyne.CanvasObject {
|
||||
return widget.NewLabel("loading…")
|
||||
},
|
||||
func(id widget.ListItemID, o fyne.CanvasObject) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
if id < 0 || id >= len(w.tasks) {
|
||||
return
|
||||
}
|
||||
t := w.tasks[id]
|
||||
o.(*widget.Label).SetText(taskTitle(t))
|
||||
},
|
||||
)
|
||||
w.list.OnSelected = func(id widget.ListItemID) {
|
||||
w.mu.Lock()
|
||||
if id < 0 || id >= len(w.tasks) {
|
||||
w.mu.Unlock()
|
||||
return
|
||||
}
|
||||
t := w.tasks[id]
|
||||
w.mu.Unlock()
|
||||
w.selectTask(t.ID)
|
||||
}
|
||||
w.taskList = NewTaskListPanel()
|
||||
w.taskList.OnSelect(func(id int64) { w.selectTask(id) })
|
||||
|
||||
quitBtn := widget.NewButtonWithIcon("Завершить", theme.LogoutIcon(), func() {
|
||||
w.saveLayout()
|
||||
@@ -135,7 +108,7 @@ func (w *Window) build() {
|
||||
w.onQuit()
|
||||
}
|
||||
})
|
||||
left := container.NewBorder(nil, quitBtn, nil, nil, w.list)
|
||||
left := container.NewBorder(nil, quitBtn, nil, nil, w.taskList.Widget())
|
||||
|
||||
// Рабочая область: детали сверху, диалог снизу (сплит 2×2 в плане).
|
||||
details := container.NewVBox(w.titleLbl, w.statusLbl, w.detailLbl)
|
||||
@@ -194,18 +167,10 @@ func (w *Window) saveLayout() {
|
||||
pref.SetFloat(splitVPref, w.vsplit.Offset)
|
||||
}
|
||||
|
||||
// taskTitle — строка в списке задач.
|
||||
func taskTitle(t storage.Task) string {
|
||||
title := t.Title
|
||||
if title == "" {
|
||||
title = "(без названия)"
|
||||
}
|
||||
return title + "\n" + string(t.Status)
|
||||
}
|
||||
|
||||
// selectTask загружает детали выбранной задачи (снимки из Store).
|
||||
func (w *Window) selectTask(id int64) {
|
||||
w.selected = id
|
||||
w.taskList.Select(id)
|
||||
w.fyneApp.Preferences().SetInt(selectedPref, int(id))
|
||||
|
||||
ctx := context.Background()
|
||||
@@ -288,15 +253,8 @@ func (w *Window) refreshList() {
|
||||
log.Printf("ui: list tasks: %v", err)
|
||||
return
|
||||
}
|
||||
w.mu.Lock()
|
||||
w.tasks = tasks
|
||||
selected := w.selected
|
||||
w.mu.Unlock()
|
||||
|
||||
if w.list != nil {
|
||||
w.list.Refresh()
|
||||
}
|
||||
_ = selected
|
||||
w.taskList.SetTasks(tasks)
|
||||
w.taskList.Select(w.selected)
|
||||
}
|
||||
|
||||
// appendConv добавляет строку в диалог (буфер ограничен).
|
||||
|
||||
Reference in New Issue
Block a user