1
0
Fork 0
mirror of https://github.com/diamondburned/cchat-gtk.git synced 2024-11-17 03:32:56 +00:00
cchat-gtk/internal/ui/service/config/config.go

127 lines
2.9 KiB
Go

// Package config contains UI widgets and renderers for cchat's Configurator
// interface.
package config
import (
"fmt"
"hash/fnv"
"io"
"strconv"
"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/text"
"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.Name())
}
file := serviceFile(conf)
if err := config.UnmarshalFromFile(file, &c); err != nil {
return nil, errors.Wrapf(err, "failed to unmarshal %s config", conf.Name())
}
if err := conf.SetConfiguration(c); err != nil {
return nil, errors.Wrapf(err, "failed to set %s config", conf.Name())
}
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.Name())
}
file := serviceFile(conf)
err = config.UnmarshalFromFile(file, &c)
err = errors.Wrapf(err, "failed to unmarshal %s config", conf.Name())
return func() {
spawn(conf.Name().String(), 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("service-%s.json", dumbHash(conf.Name()))
}
func dumbHash(name text.Rich) string {
hash := fnv.New32a()
io.WriteString(hash, name.String())
return strconv.FormatUint(uint64(hash.Sum32()), 36)
}
func spawn(name string, 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()
var title = "Configure " + name
h, _ := gtk.HeaderBarNew()
h.SetTitle(title)
h.SetShowCloseButton(true)
h.Show()
d, _ := gts.NewEmptyModalDialog()
d.SetDefaultSize(400, 300)
d.Add(b)
d.SetTitle(title)
d.SetTitlebar(h)
d.Connect("destroy", func(*gtk.Dialog) { apply(true) })
d.Show()
}