cchat-gtk/internal/ui/service/config/config.go

123 lines
2.9 KiB
Go

// Package config contains UI widgets and renderers for cchat's Configurator
// interface.
package config
import (
"fmt"
"github.com/diamondburned/cchat"
"github.com/diamondburned/cchat-gtk/internal/gts"
"github.com/diamondburned/cchat-gtk/internal/ui/config"
"github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu"
"github.com/diamondburned/cchat-gtk/internal/ui/rich"
"github.com/gotk3/gotk3/gtk"
"github.com/pkg/errors"
)
type Configurator struct {
cchat.Service
cchat.Configurator
}
func MenuItem(conf Configurator) menu.Item {
return menu.SimpleItem("Configure", func() { Spawn(conf) })
}
// Restore restores the config in the background.
func Restore(conf Configurator) {
gts.Async(func() (func(), error) {
c, err := conf.Configuration()
if err != nil {
return nil, errors.Wrapf(err, "failed to get %s config", conf.ID())
}
file := serviceFile(conf)
if err := config.UnmarshalFromFile(file, &c); err != nil {
return nil, errors.Wrapf(err, "failed to unmarshal %s config", conf.ID())
}
if err := conf.SetConfiguration(c); err != nil {
return nil, errors.Wrapf(err, "failed to set %s config", conf.ID())
}
return nil, nil
})
}
func Spawn(conf Configurator) error {
gts.Async(func() (func(), error) {
c, err := conf.Configuration()
if err != nil {
return nil, errors.Wrapf(err, "failed to get %s config", conf.ID())
}
file := serviceFile(conf)
err = config.UnmarshalFromFile(file, &c)
err = errors.Wrapf(err, "failed to unmarshal %s config", conf.ID())
return func() {
spawn(conf, c, func(finalized bool) error {
if err := conf.SetConfiguration(c); err != nil {
return err
}
if finalized {
gts.Async(func() (func(), error) {
return nil, config.MarshalToFile(file, c)
})
}
return nil
})
}, err
})
return nil
}
func serviceFile(conf Configurator) string {
return fmt.Sprintf("services/%s.json", conf.ID())
}
func spawn(c Configurator, conf map[string]string, apply func(final bool) error) {
container := newContainer(conf, func() error { return apply(false) })
container.Grid.SetVAlign(gtk.ALIGN_START)
sw, _ := gtk.ScrolledWindowNew(nil, nil)
sw.Add(container.Grid)
sw.Show()
b, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, vmargin)
b.SetMarginTop(vmargin)
b.SetMarginBottom(vmargin)
b.SetMarginStart(hmargin)
b.SetMarginEnd(hmargin)
b.PackStart(sw, true, true, 0)
b.PackStart(container.ErrHeader, false, false, 0)
b.Show()
h, _ := gtk.HeaderBarNew()
h.SetTitle("Configure " + c.ID())
h.SetShowCloseButton(true)
h.Show()
var state rich.NameContainer
state.OnUpdate(func() {
h.SetTitle("Configure " + state.String())
})
d, _ := gts.NewEmptyModalDialog()
d.SetDefaultSize(400, 300)
d.Add(b)
d.SetTitlebar(h)
// Bind the title.
state.BindNamer(d, "response", c)
// Bind the updater.
d.Connect("response", func(*gtk.Dialog) { apply(true) })
d.Show()
}