6
1
mirror of https://git.mills.io/saltyim/saltyim.git synced 2024-07-08 02:51:32 +00:00
prologic-saltyim/internal/pwa/components/saltychat.go

221 lines
5.1 KiB
Go
Raw Normal View History

package components
import (
"context"
"log"
"github.com/maxence-charriere/go-app/v9/pkg/app"
2022-03-23 04:06:56 +00:00
"github.com/mlctrez/goapp-mdc/pkg/bar"
2022-03-23 17:20:17 +00:00
"github.com/mlctrez/goapp-mdc/pkg/base"
2022-03-23 04:06:56 +00:00
"github.com/mlctrez/goapp-mdc/pkg/icon"
"github.com/mlctrez/goapp-mdc/pkg/textfield"
"go.mills.io/saltyim"
"go.mills.io/saltyim/internal/pwa/storage"
"go.yarn.social/lextwt"
)
const (
descText = `salty.im is an open specification for a new Saltpack based e2e encrypted messaging protocol and platform for secure communications with a focus on privacy, security and being self-hosted.`
)
var client *saltyim.Client
// SaltyChat ...
type SaltyChat struct {
app.Compo
2022-03-23 17:20:17 +00:00
base.JsUtil
2022-03-23 04:06:56 +00:00
isAppInstallable bool
navigation *Navigation
dialog *ModalDialog
chatBox *ChatBox
2022-03-25 04:20:16 +00:00
Friend string
chatInput *textfield.TextField
incoming chan string
2022-03-22 04:43:05 +00:00
}
func (h *SaltyChat) init(ctx app.Context) {
2022-03-25 06:49:42 +00:00
ctx.Page().SetTitle("Salty Chat")
2022-03-22 04:43:05 +00:00
}
func (h *SaltyChat) load(ctx app.Context) {
2022-03-22 04:48:54 +00:00
ctx.Page().SetTitle("Salty Chat")
2022-03-22 04:43:05 +00:00
ctx.Page().SetDescription(descText)
}
func (h *SaltyChat) OnPreRender(ctx app.Context) {
2022-03-22 04:43:05 +00:00
h.init(ctx)
h.load(ctx)
}
func (h *SaltyChat) OnResize(ctx app.Context) {
2022-03-22 04:43:05 +00:00
h.ResizeContent()
h.navigation.drawer.ActionClose(ctx)
}
func (h *SaltyChat) OnAppInstallChange(ctx app.Context) {
h.isAppInstallable = ctx.IsAppInstallable()
}
func (h *SaltyChat) OnNav(ctx app.Context) {
h.refreshMessages(ctx)
}
func (h *SaltyChat) refreshMessages(ctx app.Context) {
if ctx.Page().URL().Fragment == "" {
return
}
h.Friend = ctx.Page().URL().Fragment
h.chatBox.User = h.Friend
h.chatBox.UpdateMessages(ctx)
}
func (h *SaltyChat) OnMount(ctx app.Context) {
h.isAppInstallable = ctx.IsAppInstallable()
h.refreshMessages(ctx)
if app.IsClient {
h.connect(ctx)
}
}
func (h *SaltyChat) connect(ctx app.Context) {
if client != nil {
return
}
identity, err := GetIdentityFromState(ctx)
if err != nil {
h.dialog.ShowDialog("missing identity, please configure", err.Error())
return
}
newClient, err := saltyim.NewClient(identity.Addr(), saltyim.WithIdentityBytes(identity.Contents()))
if err != nil {
h.dialog.ShowDialog("error setting up client", err.Error())
return
}
client = newClient
ctx.Async(func() {
for msg := range client.Drain(context.Background(), "", "", "") {
s, err := lextwt.ParseSalty(msg.Text)
if err != nil {
log.Println("incoming message error", err)
continue
}
switch s := s.(type) {
case *lextwt.SaltyText:
user := s.User.String()
storage.ConversationsLocalStorage(ctx, user).Append(msg.Text)
// only update when incoming user's message is the active chat
if h.Friend == user {
h.chatBox.UpdateMessages(ctx)
} else {
// TODO: how to notify message received in background
}
}
}
})
}
func (h *SaltyChat) Render() app.UI {
2022-03-23 04:06:56 +00:00
topBar := &bar.TopAppBar{Title: "Salty IM",
Navigation: []app.HTMLButton{icon.MIMenu.Button().OnClick(func(ctx app.Context, e app.Event) {
h.navigation.drawer.ActionOpen(ctx)
})},
2022-03-23 17:08:21 +00:00
Fixed: true,
ScrollTarget: "main-content",
Actions: h.topActions(),
2022-03-23 04:06:56 +00:00
}
if h.chatBox == nil {
h.chatBox = &ChatBox{}
2022-03-25 02:11:26 +00:00
h.chatInput = &textfield.TextField{Id: "chat-input", Placeholder: ">"}
//h.friend = &textfield.TextField{Id: "friend-input", Placeholder: "send-to"}
h.dialog = &ModalDialog{}
h.navigation = &Navigation{}
2022-03-23 04:06:56 +00:00
}
h.chatBox.User = h.Friend
2022-03-23 17:08:21 +00:00
return app.Div().Body(
h.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(
h.chatBox,
app.Form().OnSubmit(h.handleSendMessage).Body(
h.chatInput,
),
h.dialog,
2022-03-23 04:06:56 +00:00
),
2022-03-22 04:43:05 +00:00
),
2022-03-23 04:06:56 +00:00
),
2022-03-23 17:08:21 +00:00
),
)
2022-03-25 04:20:16 +00:00
}
func (h *SaltyChat) handleSendMessage(ctx app.Context, e app.Event) {
2022-03-25 04:20:16 +00:00
e.PreventDefault()
msg := h.chatInput.Value
h.chatInput.Value = ""
h.focusChatInput()
//friendAddress := strings.TrimSpace(h.friend.Value)
if msg == "" || h.Friend == "" {
2022-03-25 04:20:16 +00:00
// nothing to send
return
}
storage.ContactsLocalStorage(ctx).Add(h.Friend)
2022-03-25 04:20:16 +00:00
// determine current user to send message to and use client to send the message
if client != nil {
//h.friend.Value = friendAddress
h.chatBox.User = h.Friend
ctx.Async(func() {
if err := client.Send(h.Friend, msg); err == nil {
storage.ConversationsLocalStorage(ctx, h.Friend).
Append(string(saltyim.PackMessage(client.Me(), msg)))
h.chatBox.UpdateMessages(ctx)
2022-03-25 04:20:16 +00:00
} else {
h.dialog.ShowDialog("error sending message", err.Error())
2022-03-25 04:20:16 +00:00
}
})
2022-03-25 04:20:16 +00:00
}
}
func (h *SaltyChat) focusChatInput() {
chatInputValue := h.JsUtil.JsValueAtPath(h.chatInput.Id + "-input")
chatInputValue.Set("value", "")
chatInputValue.Call("focus")
}
func (h *SaltyChat) topActions() (actions []app.HTMLButton) {
2022-03-23 17:08:21 +00:00
if h.isAppInstallable {
actions = append(actions, icon.MIDownload.Button().Title("Install PWA").
OnClick(func(ctx app.Context, e app.Event) { ctx.ShowAppInstallPrompt() }))
}
actions = append(actions, icon.MIRefresh.Button().Title("reload").
2022-03-23 17:08:21 +00:00
OnClick(func(ctx app.Context, e app.Event) { ctx.Reload() }))
return actions
}