diff options
Diffstat (limited to 'internal/ui/plugins.go')
| -rw-r--r-- | internal/ui/plugins.go | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/internal/ui/plugins.go b/internal/ui/plugins.go new file mode 100644 index 0000000..cf29f37 --- /dev/null +++ b/internal/ui/plugins.go @@ -0,0 +1,179 @@ +package ui + +import ( + "strings" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/dialog" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/storage" + "fyne.io/fyne/v2/widget" + + "github.com/shiv/internal/events" + "github.com/shiv/internal/store" + "github.com/shiv/internal/ui/widgets" +) + +type pluginsTab struct { + projectStore *store.Store + bus *events.Bus + win fyne.Window +} + +func newPluginsTab(projectStore *store.Store, bus *events.Bus, win fyne.Window) *pluginsTab { + return &pluginsTab{ + projectStore: projectStore, + bus: bus, + win: win, + } +} + +func (t *pluginsTab) build() fyne.CanvasObject { + var plugins []store.PluginEntry + selectedIdx := -1 + + logView := widgets.NewTextView() + logView.SetWindow(t.win) + + toggleBtn := widget.NewButton("Disable", nil) + toggleBtn.Disable() + + var pluginList *widget.List + + refreshLogs := func() { + if selectedIdx < 0 || selectedIdx >= len(plugins) { + logView.SetText("") + return + } + lines := t.projectStore.PluginLogs(plugins[selectedIdx].Name) + logView.SetText(strings.Join(lines, "\n")) + } + + refreshAll := func() { + entries, err := t.projectStore.AllPlugins() + if err != nil { + return + } + plugins = entries + pluginList.Refresh() + + // Keep toggle button label in sync after external state change. + if selectedIdx >= 0 && selectedIdx < len(plugins) { + if plugins[selectedIdx].Enabled { + toggleBtn.SetText("Disable") + } else { + toggleBtn.SetText("Enable") + } + toggleBtn.Enable() + } + + refreshLogs() + } + + pluginList = widget.NewList( + func() int { return len(plugins) }, + func() fyne.CanvasObject { + return container.NewHBox( + widget.NewLabel(""), + widget.NewLabel(""), + ) + }, + func(id widget.ListItemID, item fyne.CanvasObject) { + if id >= len(plugins) { + return + } + p := plugins[id] + box := item.(*fyne.Container) + status := box.Objects[0].(*widget.Label) + name := box.Objects[1].(*widget.Label) + if p.Enabled { + status.SetText("✓") + status.Importance = widget.SuccessImportance + } else { + status.SetText("✗") + status.Importance = widget.DangerImportance + } + name.SetText(p.Name) + }, + ) + + pluginList.OnSelected = func(id widget.ListItemID) { + selectedIdx = id + if id >= len(plugins) { + toggleBtn.Disable() + return + } + if plugins[id].Enabled { + toggleBtn.SetText("Disable") + } else { + toggleBtn.SetText("Enable") + } + toggleBtn.Enable() + refreshLogs() + } + + pluginList.OnUnselected = func(_ widget.ListItemID) { + selectedIdx = -1 + toggleBtn.Disable() + logView.SetText("") + } + + toggleBtn.OnTapped = func() { + if selectedIdx < 0 || selectedIdx >= len(plugins) { + return + } + p := plugins[selectedIdx] + t.bus.EmitSetPluginEnabled(events.SetPluginEnabledEvent{ + Name: p.Name, + Enabled: !p.Enabled, + }) + } + + addBtn := widget.NewButton("Add", func() { + fd := dialog.NewFileOpen(func(uc fyne.URIReadCloser, err error) { + if err != nil || uc == nil { + return + } + uc.Close() + t.bus.EmitLoadPlugin(events.LoadPluginEvent{ + SourcePath: uc.URI().Path(), + }) + }, t.win) + fd.SetFilter(storage.NewExtensionFileFilter([]string{".lua"})) + fd.Show() + }) + + // Listen for plugin state and log changes from the store. + go func() { + for range t.projectStore.PluginEntries { + fyne.Do(refreshAll) + } + }() + + // Initial population. + refreshAll() + + toolbar := container.New( + layout.NewCustomPaddedLayout(8, 8, 0, 0), + container.NewHBox(addBtn, toggleBtn), + ) + + leftPane := container.NewBorder( + newBoldLabel("Plugins"), + toolbar, + nil, nil, + pluginList, + ) + + rightPane := container.NewBorder( + newBoldLabel("Log"), + nil, nil, nil, + logView.Build(), + ) + + split := container.NewHSplit(leftPane, rightPane) + split.SetOffset(0.3) + + return split +} |
