mirror of
https://git.mills.io/saltyim/saltyim.git
synced 2024-06-16 11:58:24 +00:00
Add support for new contacts appearing in contact list automatically (#89)
Co-authored-by: James Mills <prologic@shortcircuit.net.au> Co-authored-by: mlctrez <mlctrez@gmail.com> Reviewed-on: https://git.mills.io/saltyim/saltyim/pulls/89
This commit is contained in:
parent
7fc5e7184b
commit
f9fa628e75
7
Makefile
7
Makefile
@ -30,14 +30,19 @@ preflight: ## Run preflight checks to ensure you have the right build tools
|
||||
@./preflight.sh
|
||||
|
||||
deps: ## Install any dependencies required
|
||||
@$(GOCMD) install github.com/jsha/minica@latest
|
||||
@$(GOCMD) install git.mills.io/prologic/devdns@latest
|
||||
|
||||
dev : DEBUG=1
|
||||
dev : build ## Build debug versions of the cli and server
|
||||
@./salty-chat -v
|
||||
@./saltyd -v
|
||||
|
||||
certs: certs/minica-key.pem certs/minica.pem certs/salty.home.arpa/key.pem certs/salty.home.arpa/cert.pem
|
||||
@/bin/sh -c 'cd certs && minica --domains salty.home.arpa'
|
||||
|
||||
pwa-dev : DEBUG=1
|
||||
pwa-dev : build ## Build debug version of saltyd and PWA
|
||||
pwa-dev : build certs ## Build debug version of saltyd and PWA
|
||||
@CGO_ENABLED=1 $(GOCMD) build -tags "embed" ./cmd/saltyd/...
|
||||
@./saltyd -D -b :https -u https://salty.home.arpa \
|
||||
--tls --tls-key ./certs/salty.home.arpa/key.pem \
|
||||
|
@ -306,6 +306,13 @@ func (cli *Client) Subscribe(ctx context.Context, extraenvs, prehook, posthook s
|
||||
return msgs
|
||||
}
|
||||
|
||||
// Lookup performs a lookup for a user's address and config
|
||||
// If the user has an address already cached, the cached addr
|
||||
// is returned, otherwise a full lookup is done.
|
||||
func (cli *Client) Lookup(user string) (*Addr, error) {
|
||||
return cli.getAddr(user)
|
||||
}
|
||||
|
||||
// Send sends an encrypted message to the specified user
|
||||
func (cli *Client) Send(user, msg string) error {
|
||||
addr, err := cli.getAddr(user)
|
||||
|
@ -1,6 +1,8 @@
|
||||
package components
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/maxence-charriere/go-app/v9/pkg/app"
|
||||
@ -11,12 +13,16 @@ import (
|
||||
"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
|
||||
@ -34,6 +40,7 @@ func (c *Configuration) readState(ctx app.Context) {
|
||||
}
|
||||
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) {
|
||||
@ -79,6 +86,8 @@ func (c *Configuration) Render() app.UI {
|
||||
&button.Button{Icon: string(icon.MIUpdate), Label: "update identity",
|
||||
Outlined: true, Raised: true, Callback: c.updateIdentity()},
|
||||
app.Hr(),
|
||||
app.H4().Text("remove contacts and storage"),
|
||||
c.buildDeleteContacts(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -87,6 +96,31 @@ func (c *Configuration) Render() app.UI {
|
||||
|
||||
}
|
||||
|
||||
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()
|
||||
ctx.Defer(func(context app.Context) {
|
||||
ctx.NewAction("navigation.update")
|
||||
c.Update()
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
app.Br(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Configuration) newIdentity() func(button app.HTMLButton) {
|
||||
return func(button app.HTMLButton) {
|
||||
button.OnClick(func(ctx app.Context, e app.Event) {
|
||||
|
@ -23,29 +23,35 @@ func (n *Navigation) Render() app.UI {
|
||||
List: &list.List{Type: list.Navigation, Id: "navigationList"},
|
||||
}
|
||||
}
|
||||
|
||||
items := list.Items{
|
||||
{Type: list.ItemTypeAnchor, Graphic: icon.MISettings, Href: "/config", Text: "settings"},
|
||||
{Type: list.ItemTypeAnchor, Graphic: icon.MIPersonAdd, Href: "/newchat", Text: "new chat"},
|
||||
{Type: list.ItemTypeAnchor, Graphic: icon.MISettings, Href: "/config", Text: "Settings"},
|
||||
{Type: list.ItemTypeAnchor, Graphic: icon.MIPersonAdd, Href: "/newchat", Text: "New Chat"},
|
||||
{Type: list.ItemTypeDivider},
|
||||
}
|
||||
|
||||
for _, contact := range n.Contacts {
|
||||
i := &list.Item{Type: list.ItemTypeAnchor, Graphic: icon.MIPerson, Href: "/#" + contact, Text: contact}
|
||||
items = append(items, i)
|
||||
}
|
||||
|
||||
n.drawer.List.Items = items.UIList()
|
||||
|
||||
return n.drawer
|
||||
}
|
||||
|
||||
func (n *Navigation) LoadFromStorage(ctx app.Context) {
|
||||
n.Contacts = storage.ContactsLocalStorage(ctx).List()
|
||||
}
|
||||
|
||||
func (n *Navigation) OnMount(ctx app.Context) {
|
||||
n.items.SelectHref(ctx.Page().URL().Path)
|
||||
n.Contacts = storage.ContactsLocalStorage(ctx).List()
|
||||
n.LoadFromStorage(ctx)
|
||||
ctx.Handle(string(list.Select), func(context app.Context, action app.Action) {
|
||||
if action.Value == n.drawer.List {
|
||||
n.drawer.ActionClose(context)
|
||||
}
|
||||
})
|
||||
ctx.Handle("navigation.update", n.navigationUpdate)
|
||||
}
|
||||
|
||||
func (n *Navigation) navigationUpdate(ctx app.Context, action app.Action) {
|
||||
n.drawer.List.Update()
|
||||
}
|
||||
|
@ -45,9 +45,9 @@ func (n *NewChat) Render() app.UI {
|
||||
app.Div().Class("main-content").ID("main-content").Body(
|
||||
topBar.Main().Body(
|
||||
app.Div().ID("wrapper").Body(
|
||||
app.H4().Text("new chat"),
|
||||
app.H4().Text("New Chat"),
|
||||
n.user,
|
||||
&button.Button{Icon: string(icon.MICreate), Label: "new chat",
|
||||
&button.Button{Icon: string(icon.MICreate), Label: "New Chat",
|
||||
Outlined: true, Raised: true, Callback: n.newChat()},
|
||||
n.dialog,
|
||||
),
|
||||
|
@ -32,8 +32,6 @@ type SaltyChat struct {
|
||||
|
||||
Friend string
|
||||
chatInput *textfield.TextField
|
||||
|
||||
incoming chan string
|
||||
}
|
||||
|
||||
func (h *SaltyChat) init(ctx app.Context) {
|
||||
@ -82,14 +80,19 @@ func (h *SaltyChat) OnMount(ctx app.Context) {
|
||||
h.refreshMessages(ctx)
|
||||
if app.IsClient {
|
||||
h.connect(ctx)
|
||||
} else {
|
||||
log.Println("app not running as a client?")
|
||||
}
|
||||
}
|
||||
|
||||
func (h *SaltyChat) connect(ctx app.Context) {
|
||||
log.Println("connect()")
|
||||
|
||||
if client != nil {
|
||||
log.Println("already have a connected client")
|
||||
return
|
||||
}
|
||||
log.Println("creating new client")
|
||||
|
||||
identity, err := GetIdentityFromState(ctx)
|
||||
if err != nil {
|
||||
@ -115,18 +118,36 @@ func (h *SaltyChat) connect(ctx app.Context) {
|
||||
switch s := s.(type) {
|
||||
case *lextwt.SaltyText:
|
||||
user := s.User.String()
|
||||
storage.ContactsLocalStorage(ctx).Add(user)
|
||||
storage.ConversationsLocalStorage(ctx, user).Append(msg.Text)
|
||||
|
||||
h.updateNavigation(ctx, user)
|
||||
|
||||
// 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
|
||||
// TODO: Creates some initial content of the new chat
|
||||
// to give the user a change to Accept/Reject the contact.
|
||||
log.Printf("new incoming chat from %s", user)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (h *SaltyChat) updateNavigation(ctx app.Context, user string) {
|
||||
var existingFound bool
|
||||
for _, existing := range h.navigation.Contacts {
|
||||
if user == existing {
|
||||
existingFound = true
|
||||
}
|
||||
}
|
||||
if !existingFound {
|
||||
ctx.NewAction("navigation.update")
|
||||
}
|
||||
}
|
||||
|
||||
func (h *SaltyChat) Render() app.UI {
|
||||
|
||||
topBar := &bar.TopAppBar{Title: "Salty IM",
|
||||
@ -141,7 +162,6 @@ func (h *SaltyChat) Render() app.UI {
|
||||
if h.chatBox == nil {
|
||||
h.chatBox = &ChatBox{}
|
||||
h.chatInput = &textfield.TextField{Id: "chat-input", Placeholder: ">"}
|
||||
//h.friend = &textfield.TextField{Id: "friend-input", Placeholder: "send-to"}
|
||||
h.dialog = &ModalDialog{}
|
||||
h.navigation = &Navigation{}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ type Conversations interface {
|
||||
Read() []string
|
||||
Append(line string)
|
||||
Update(lines []string)
|
||||
Delete()
|
||||
}
|
||||
|
||||
type conversations struct {
|
||||
@ -36,15 +37,21 @@ func (c *conversations) Append(line string) {
|
||||
c.Update(append(readConversations(c.state, c.addr), line))
|
||||
}
|
||||
|
||||
func (c *conversations) Delete() {
|
||||
c.state.DelState(conversationKey(c.addr))
|
||||
}
|
||||
|
||||
func readConversations(state StateOperations, addr string) []string {
|
||||
conversationKey := fmt.Sprintf(ConversationsKey, sha256.Sum256([]byte(addr)))
|
||||
var conversations []string
|
||||
state.GetState(conversationKey, &conversations)
|
||||
state.GetState(conversationKey(addr), &conversations)
|
||||
return conversations
|
||||
}
|
||||
|
||||
func conversationKey(addr string) string {
|
||||
return fmt.Sprintf(ConversationsKey, sha256.Sum256([]byte(addr)))
|
||||
}
|
||||
func updateConversations(state StateOperations, addr string, conversations []string) {
|
||||
conversationKey := fmt.Sprintf(ConversationsKey, sha256.Sum256([]byte(addr)))
|
||||
state.SetState(conversationKey, conversations, app.Persist, app.Encrypt)
|
||||
state.SetState(conversationKey(addr), conversations, app.Persist, app.Encrypt)
|
||||
}
|
||||
|
||||
func ConversationsLocalStorage(state StateOperations, addr string) Conversations {
|
||||
|
@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7075736b07e9bd858ff854adfd5ca2814c029875d1346a0f09a8946dc11dec41
|
||||
size 26695945
|
||||
oid sha256:e997726e559f96e73aa2ac3302a11e7aaba80e2fb624c998bc3af0296a7e98e6
|
||||
size 26674321
|
||||
|
Loading…
Reference in New Issue
Block a user