package components import ( "crypto/sha256" "fmt" "log" "github.com/maxence-charriere/go-app/v9/pkg/app" "github.com/mlctrez/goapp-mdc/pkg/bar" "github.com/mlctrez/goapp-mdc/pkg/base" "github.com/mlctrez/goapp-mdc/pkg/button" "github.com/mlctrez/goapp-mdc/pkg/icon" "github.com/mlctrez/goapp-mdc/pkg/textarea" "github.com/mlctrez/goapp-mdc/pkg/textfield" "go.mills.io/saltyim" "go.mills.io/saltyim/internal/pwa/storage" ) type Configuration struct { app.Compo base.JsUtil // to support removal Contacts []string navigation *Navigation // components user *textfield.TextField identity *textarea.TextArea } func (c *Configuration) readState(ctx app.Context) { identity, err := GetIdentityFromState(ctx) if err != nil { // TODO: display dialog log.Println("state read error", err) return } c.identity.Value = string(identity.Contents()) c.user.Value = identity.Addr().String() c.Contacts = storage.ContactsLocalStorage(ctx).List() } func (c *Configuration) OnMount(ctx app.Context) { if app.IsClient { c.readState(ctx) } } func (c *Configuration) Render() app.UI { topBar := &bar.TopAppBar{Title: "Salty IM", Navigation: []app.HTMLButton{icon.MIMenu.Button().OnClick(func(ctx app.Context, e app.Event) { c.navigation.drawer.ActionOpen(ctx) })}, Fixed: true, ScrollTarget: "main-content", Actions: c.topActions(), } if c.user == nil { c.user = &textfield.TextField{Id: "config-user", Label: "User in the form user@domain"} c.identity = textarea.New("identity").Size(5, 100).Label("identity").MaxLength(1024) c.identity.WithCallback(func(in app.HTMLTextarea) { in.OnChange(c.identity.ValueTo(&c.identity.Value)) }) c.navigation = &Navigation{} } return app.Div().Body( c.navigation, app.Div().Class("mdc-drawer-app-content").Body( &AppUpdateBanner{}, topBar, app.Div().Class("main-content").ID("main-content").Body( topBar.Main().Body( app.Div().ID("wrapper").Body( app.H4().Text("configuration"), c.user, &button.Button{Icon: string(icon.MICreate), Label: "new identity", Outlined: true, Raised: true, Callback: c.newIdentity()}, app.Br(), c.identity, &button.Button{Icon: string(icon.MIUpdate), Label: "update identity", Outlined: true, Raised: true, Callback: c.updateIdentity()}, app.Br(), app.H4().Text("register with salty@domain for above identity"), &button.Button{Icon: string(icon.MICreate), Label: "register", Outlined: true, Raised: true, Callback: c.registerIdentity()}, app.Hr(), app.H4().Text("remove contacts and storage"), c.buildDeleteContacts(), ), ), ), ), ) } func (c *Configuration) buildDeleteContacts() app.UI { return app.Range(c.Contacts).Slice(func(i int) app.UI { return app.Div().Body( &button.Button{ Id: fmt.Sprintf("%x", sha256.Sum256([]byte(c.Contacts[i]))), Icon: string(icon.MIDelete), Label: c.Contacts[i], Raised: true, Outlined: true, Callback: func(button app.HTMLButton) { button.OnClick(func(ctx app.Context, e app.Event) { storage.ConversationsLocalStorage(ctx, c.Contacts[i]).Delete() storage.ContactsLocalStorage(ctx).Remove(c.Contacts[i]) c.Contacts = storage.ContactsLocalStorage(ctx).List() c.navigation.UpdateAction(ctx) ctx.Defer(func(context app.Context) { c.Update() }) }) }, }, app.Br(), ) }) } func (c *Configuration) registerIdentity() func(button app.HTMLButton) { return func(button app.HTMLButton) { button.OnClick(func(ctx app.Context, e app.Event) { identity, err := GetIdentityFromState(ctx) if err != nil { // TODO: pop dialog log.Println("error", err) return } // not using client since that's not setup until we have an identity, might break the existing // flow registerClient, err := saltyim.NewClient(identity.Addr(), saltyim.WithClientIdentity(saltyim.WithIdentityBytes(identity.Contents()))) if err != nil { // TODO: pop dialog log.Println("error", err) return } err = registerClient.Register() if err != nil { // TODO: pop dialog log.Println("error", err) return } }) } } func (c *Configuration) newIdentity() func(button app.HTMLButton) { return func(button app.HTMLButton) { button.OnClick(func(ctx app.Context, e app.Event) { addr, err := saltyim.ParseAddr(c.user.Value) if err != nil { // TODO: pop dialog log.Println("error", err) return } identity, err := saltyim.CreateIdentity(saltyim.WithIdentityAddr(addr)) if err != nil { // TODO: pop dialog log.Println("error", err) return } c.identity.Value = string(identity.Contents()) err = SetIdentityToState(ctx, identity) if err != nil { // TODO: pop dialog log.Println("error", err) return } c.identity.Update() }) } } func (c *Configuration) updateIdentity() func(button app.HTMLButton) { return func(button app.HTMLButton) { button.OnClick(func(ctx app.Context, e app.Event) { identityString := c.identity.Value identity, err := saltyim.GetIdentity(saltyim.WithIdentityBytes([]byte(identityString))) if err != nil { // TODO: pop dialog log.Println("error", err) return } err = SetIdentityToState(ctx, identity) if err != nil { // TODO: pop dialog log.Println("error", err) return } c.user.Value = identity.Addr().String() c.user.Update() }) } } func (c *Configuration) topActions() (actions []app.HTMLButton) { actions = append(actions, icon.MIRefresh.Button().Title("reload"). OnClick(func(ctx app.Context, e app.Event) { ctx.Reload() })) return actions }