diff --git a/go/gobjects/message.go b/go/gobjects/message.go deleted file mode 100644 index 01284ffb..00000000 --- a/go/gobjects/message.go +++ /dev/null @@ -1,16 +0,0 @@ -package gobjects - -import "time" - -type Message struct { - Handle string - From string - DisplayName string - Message string - Image string - FromMe bool - MessageID string - Timestamp time.Time - Acknowledged bool - Error bool -} diff --git a/go/characters/appEventListener.go b/go/handlers/appHandler.go similarity index 86% rename from go/characters/appEventListener.go rename to go/handlers/appHandler.go index b87abe17..6b2ce139 100644 --- a/go/characters/appEventListener.go +++ b/go/handlers/appHandler.go @@ -1,18 +1,17 @@ -package characters +package handlers import ( "cwtch.im/cwtch/app/plugins" "cwtch.im/cwtch/event" "cwtch.im/ui/go/constants" - "cwtch.im/ui/go/cwutil" - "cwtch.im/ui/go/gothings" "cwtch.im/ui/go/the" + "cwtch.im/ui/go/ui" "git.openprivacy.ca/openprivacy/libricochet-go/log" "os" "strconv" ) -func AppEventListener(gcd *gothings.GrandCentralDispatcher, subscribed chan bool) { +func App(gcd *ui.GrandCentralDispatcher, subscribed chan bool) { q := event.NewQueue() the.AppBus.Subscribe(event.NewPeer, q) the.AppBus.Subscribe(event.PeerError, q) @@ -78,20 +77,25 @@ func AppEventListener(gcd *gothings.GrandCentralDispatcher, subscribed chan bool the.EventBus = the.CwtchApp.GetEventBus(onion) incSubscribed := make(chan bool) - go IncomingListener(&gcd.UIState, incSubscribed) + go PeerHandler(&gcd.UIManager, incSubscribed) <-incSubscribed - gcd.UpdateMyProfile(the.Peer.GetProfile().Name, the.Peer.GetProfile().Onion, cwutil.RandomProfileImage(the.Peer.GetProfile().Onion)) + pic, exists := the.Peer.GetAttribute(constants.Picture) + if !exists { + pic = ui.RandomProfileImage(the.Peer.GetProfile().Onion) + the.Peer.SetAttribute(constants.Picture, pic) + } + gcd.UpdateMyProfile(the.Peer.GetProfile().Name, the.Peer.GetProfile().Onion, pic) contacts := the.Peer.GetContacts() for i := range contacts { - gcd.UIState.AddContact(contacts[i]) + gcd.UIManager.AddContact(contacts[i]) } groups := the.Peer.GetGroups() for i := range groups { // Only join servers for active and explicitly accepted groups. - gcd.UIState.AddContact(groups[i]) + gcd.UIManager.AddContact(groups[i]) } if e.Data[event.Status] != "running" { diff --git a/go/characters/incominglistener.go b/go/handlers/peerHandler.go similarity index 60% rename from go/characters/incominglistener.go rename to go/handlers/peerHandler.go index ce183c2a..ad0a70a9 100644 --- a/go/characters/incominglistener.go +++ b/go/handlers/peerHandler.go @@ -1,18 +1,15 @@ -package characters +package handlers import ( "cwtch.im/cwtch/event" "cwtch.im/cwtch/protocol/connections" - "cwtch.im/ui/go/constants" - "cwtch.im/ui/go/cwutil" - "cwtch.im/ui/go/gobjects" - "cwtch.im/ui/go/gothings" "cwtch.im/ui/go/the" + "cwtch.im/ui/go/ui" "git.openprivacy.ca/openprivacy/libricochet-go/log" "time" ) -func IncomingListener(uiState *gothings.InterfaceState, subscribed chan bool) { +func PeerHandler(uiManager *ui.Manager, subscribed chan bool) { q := event.NewQueue() the.EventBus.Subscribe(event.NewMessageFromPeer, q) the.EventBus.Subscribe(event.PeerAcknowledgement, q) @@ -31,76 +28,48 @@ func IncomingListener(uiState *gothings.InterfaceState, subscribed chan bool) { switch e.EventType { case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampReceived]) - uiState.AddMessage(&gobjects.Message{ - Handle: e.Data[event.RemotePeer], - From: e.Data[event.RemotePeer], - Message: e.Data[event.Data], - Image: cwutil.RandomProfileImage(e.Data[event.RemotePeer]), - Timestamp: ts, - }) + uiManager.AddMessage(e.Data[event.RemotePeer], e.Data[event.RemotePeer], e.Data[event.Data], false, e.EventID, ts, true) if the.Peer.GetContact(e.Data[event.RemotePeer]) == nil { the.Peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false) } case event.PeerAcknowledgement: - uiState.Acknowledge(e.Data[event.EventID]) + uiManager.Acknowledge(e.Data[event.EventID]) case event.NewMessageFromGroup: //event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer - var name string - var exists bool - ctc := the.Peer.GetContact(e.Data[event.RemotePeer]) - if ctc != nil { - name, exists = ctc.GetAttribute(constants.Nick) - if !exists || name == "" { - name = e.Data[event.RemotePeer] - } - } else { - name = e.Data[event.RemotePeer] - } - ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent]) - uiState.AddMessage(&gobjects.Message{ - MessageID: e.Data[event.Signature], - Handle: e.Data[event.GroupID], - From: e.Data[event.RemotePeer], - Message: e.Data[event.Data], - Image: cwutil.RandomProfileImage(e.Data[event.RemotePeer]), - FromMe: e.Data[event.RemotePeer] == the.Peer.GetProfile().Onion, - Timestamp: ts, - Acknowledged: true, - DisplayName: name, - }) + uiManager.AddMessage(e.Data[event.GroupID], e.Data[event.RemotePeer], e.Data[event.Data], e.Data[event.RemotePeer] == the.Peer.GetProfile().Onion, e.Data[event.Signature], ts, true) case event.NewGroupInvite: gid, err := the.Peer.GetProfile().ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer]) group := the.Peer.GetGroup(gid) if err == nil && group != nil { - uiState.AddContact(gid) + uiManager.AddContact(gid) } case event.PeerCreated: onion := e.Data[event.RemotePeer] - uiState.AddContact(onion) + uiManager.AddContact(onion) case event.SendMessageToGroupError: - uiState.AddSendMessageError(e.Data[event.GroupServer], e.Data[event.Signature], e.Data[event.Error]) + uiManager.AddSendMessageError(e.Data[event.GroupServer], e.Data[event.Signature], e.Data[event.Error]) case event.SendMessageToPeerError: - uiState.AddSendMessageError(e.Data[event.RemotePeer], e.Data[event.EventID], e.Data[event.Error]) + uiManager.AddSendMessageError(e.Data[event.RemotePeer], e.Data[event.EventID], e.Data[event.Error]) case event.PeerStateChange: cxnState := connections.ConnectionStateToType[e.Data[event.ConnectionState]] - // if it's not in the.Peer it's new. Only add once Authed + // if it's not in the.PeerHandler it's new. Only add once Authed if _, exists := the.Peer.GetProfile().Contacts[e.Data[event.RemotePeer]]; !exists { // Contact does not exist, we will add them but we won't know who they are until they are authenticated // So if we get any other state from an unknown contact we do nothing // (the next exists check will fail) if cxnState == connections.AUTHENTICATED { the.Peer.AddContact(e.Data[event.RemotePeer], e.Data[event.RemotePeer], false) - uiState.AddContact(e.Data[event.RemotePeer]) + uiManager.AddContact(e.Data[event.RemotePeer]) } } - // if it's in the.Peer its either existing and needs an update or not in the UI and needs to be added + // if it's in the.PeerHandler its either existing and needs an update or not in the UI and needs to be added if contact, exists := the.Peer.GetProfile().Contacts[e.Data[event.RemotePeer]]; exists { contact.State = e.Data[event.ConnectionState] - uiState.UpdateContactStatus(contact.Onion, int(cxnState), false) + uiManager.UpdateContactStatus(contact.Onion, int(cxnState), false) } case event.ServerStateChange: @@ -115,7 +84,7 @@ func IncomingListener(uiState *gothings.InterfaceState, subscribed chan bool) { if state == connections.AUTHENTICATED { loading = true } - uiState.UpdateContactStatus(group.GroupID, int(state), loading) + uiManager.UpdateContactStatus(group.GroupID, int(state), loading) } else { log.Errorf("found group that is nil :/") } diff --git a/go/gothings/android/CwtchActivity.go b/go/ui/android/CwtchActivity.go similarity index 100% rename from go/gothings/android/CwtchActivity.go rename to go/ui/android/CwtchActivity.go diff --git a/go/gothings/gcd.go b/go/ui/gcd.go similarity index 92% rename from go/gothings/gcd.go rename to go/ui/gcd.go index 85085a74..af42c749 100644 --- a/go/gothings/gcd.go +++ b/go/ui/gcd.go @@ -1,13 +1,11 @@ -package gothings +package ui import ( "cwtch.im/cwtch/event" "cwtch.im/cwtch/protocol/connections" "cwtch.im/ui/go/constants" - "cwtch.im/ui/go/cwutil" "github.com/therecipe/qt/qml" - "cwtch.im/ui/go/gobjects" "cwtch.im/ui/go/the" "encoding/base32" "git.openprivacy.ca/openprivacy/libricochet-go/log" @@ -19,7 +17,7 @@ import ( type GrandCentralDispatcher struct { core.QObject - UIState InterfaceState + UIManager Manager QMLEngine *qml.QQmlApplicationEngine Translator *core.QTranslator @@ -109,18 +107,7 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID string) { var err error mID, err = the.Peer.SendMessageToGroupTracked(this.CurrentOpenConversation(), message) - this.UIState.AddMessage(&gobjects.Message{ - this.CurrentOpenConversation(), - "me", - "", - message, - "", - true, - mID, - time.Now(), - false, - false, - }) + this.UIManager.AddMessage(this.CurrentOpenConversation(), "me", message, true, mID, time.Now(), false) if err != nil { this.InvokePopup("failed to send message " + err.Error()) @@ -130,18 +117,7 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID string) { to := this.CurrentOpenConversation() mID = the.Peer.SendMessageToPeer(to, message) - this.UIState.AddMessage(&gobjects.Message{ - to, - "me", - "", - message, - "", - true, - mID, - time.Now(), - false, - false, - }) + this.UIManager.AddMessage(to, "me", message, true, mID, time.Now(), false) } } @@ -182,24 +158,16 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) { } else { handle = tl[i].PeerID } - var name string - var exists bool - ctc := the.Peer.GetContact(tl[i].PeerID) - if ctc != nil { - name, exists = ctc.GetAttribute(constants.Nick) - if !exists || name == "" { - name = tl[i].PeerID - } - } else { - name = tl[i].PeerID - } + + name := getOrDefault(tl[i].PeerID, constants.Nick, tl[i].PeerID) + image := getProfilePic(tl[i].PeerID) this.PrependMessage( handle, tl[i].PeerID, name, tl[i].Message, - cwutil.RandomProfileImage(tl[i].PeerID), + image, string(tl[i].Signature), tl[i].PeerID == the.Peer.GetProfile().Onion, tl[i].Timestamp.Format(constants.TIME_FORMAT), @@ -233,24 +201,15 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) { from = "me" } - var displayname string - ctc := the.Peer.GetContact(messages[i].PeerID) - if ctc != nil { - var exists bool - displayname, exists = ctc.GetAttribute(constants.Nick) - if !exists || displayname == "" { - displayname = messages[i].PeerID - } - } else { - displayname = messages[i].PeerID - } + displayname := getOrDefault(messages[i].PeerID, constants.Nick, messages[i].PeerID) + image := getProfilePic(messages[i].PeerID) this.AppendMessage( from, messages[i].PeerID, displayname, messages[i].Message, - cwutil.RandomProfileImage(handle), + image, string(messages[i].Signature), fromMe, messages[i].Timestamp.Format(constants.TIME_FORMAT), @@ -397,7 +356,7 @@ func (this *GrandCentralDispatcher) importString(str string) { _, err := base32.StdEncoding.DecodeString(strings.ToUpper(onion[:56])) if err != nil { log.Debugln(err) - this.InvokePopup("bad format. missing characters?") + this.InvokePopup("bad format. missing handlers?") return } @@ -410,7 +369,7 @@ func (this *GrandCentralDispatcher) importString(str string) { the.Peer.PeerWithOnion(onion) } - this.UIState.AddContact(onion) + this.UIManager.AddContact(onion) } func (this *GrandCentralDispatcher) popup(str string) { @@ -431,7 +390,7 @@ func (this *GrandCentralDispatcher) createGroup(server, groupName string) { return } - this.UIState.AddContact(groupID) + this.UIManager.AddContact(groupID) the.Peer.SetGroupAttribute(groupID, constants.Nick, groupName) @@ -480,7 +439,7 @@ func (this *GrandCentralDispatcher) acceptGroup(groupID string) { func (this *GrandCentralDispatcher) setAttribute(onion, key, value string) { the.Peer.SetContactAttribute(onion, key, value) - this.UIState.UpdateContactAttribute(onion, key, value) + this.UIManager.UpdateContactAttribute(onion, key, value) } func (this *GrandCentralDispatcher) blockUnknownPeers() { diff --git a/go/gothings/uistate.go b/go/ui/manager.go similarity index 50% rename from go/gothings/uistate.go rename to go/ui/manager.go index 745b1952..bf4ee769 100644 --- a/go/gothings/uistate.go +++ b/go/ui/manager.go @@ -1,11 +1,9 @@ -package gothings +package ui import ( "cwtch.im/cwtch/model" "cwtch.im/cwtch/protocol/connections" "cwtch.im/ui/go/constants" - "cwtch.im/ui/go/cwutil" - "cwtch.im/ui/go/gobjects" "cwtch.im/ui/go/the" "git.openprivacy.ca/openprivacy/libricochet-go/log" "runtime/debug" @@ -20,6 +18,21 @@ func isPeer(id string) bool { return len(id) == 56 } +func getOrDefault(id, key, defaultVal string) string { + var val string + var ok bool + if isGroup(id) { + val, ok = the.Peer.GetGroupAttribute(id, key) + } else { + val, ok = the.Peer.GetContactAttribute(id, key) + } + if ok { + return val + } else { + return defaultVal + } +} + func getWithSetDefault(id string, key, defaultVal string) string { var val string var ok bool @@ -49,11 +62,27 @@ func initLastReadTime(id string) time.Time { } func initProfilePicture(id string) string { - log.Infof("initProfilePic: %v\n", id) if isGroup(id) { - return getWithSetDefault(id, constants.Picture, cwutil.RandomGroupImage(id)) + return getWithSetDefault(id, constants.Picture, RandomGroupImage(id)) } else { - return getWithSetDefault(id, constants.Picture, cwutil.RandomProfileImage(id)) + return getWithSetDefault(id, constants.Picture, RandomProfileImage(id)) + } +} + +// getProfilePic supplies a profile pic to use. In groups we may not have a contact so it will generate one +func getProfilePic(id string) string { + if isGroup(id) { + if pic, exists := the.Peer.GetGroupAttribute(id, constants.Picture); !exists { + return RandomGroupImage(id) + } else { + return pic + } + } else { + if pic, exists := the.Peer.GetContactAttribute(id, constants.Picture); !exists { + return RandomProfileImage(id) + } else { + return pic + } } } @@ -78,20 +107,19 @@ func countUnread(messages []model.Message, lastRead time.Time) int { return count } -type InterfaceState struct { - parentGcd *GrandCentralDispatcher +type Manager struct { + gcd *GrandCentralDispatcher } -func NewUIState(gcd *GrandCentralDispatcher) (uis InterfaceState) { - uis = InterfaceState{gcd} - return +func NewManager(gcd *GrandCentralDispatcher) Manager { + return Manager{gcd} } -func (this *InterfaceState) Acknowledge(mID string) { - this.parentGcd.Acknowledged(mID) +func (this *Manager) Acknowledge(mID string) { + this.gcd.Acknowledged(mID) } -func (this *InterfaceState) AddContact(Handle string) { +func (this *Manager) AddContact(Handle string) { if isGroup(Handle) { group := the.Peer.GetGroup(Handle) if group != nil { @@ -103,7 +131,7 @@ func (this *InterfaceState) AddContact(Handle string) { nick = Handle } - this.parentGcd.AddContact(Handle, nick, picture, group.GroupServer, unread, int(connections.ConnectionStateToType[group.State]), false, false) + this.gcd.AddContact(Handle, nick, picture, group.GroupServer, unread, int(connections.ConnectionStateToType[group.State]), false, false) } return } else if !isPeer(Handle) { @@ -122,41 +150,48 @@ func (this *InterfaceState) AddContact(Handle string) { nick = Handle } - this.parentGcd.AddContact(Handle, nick, picture, "", unread, int(connections.ConnectionStateToType[contact.State]), contact.Blocked, false) + this.gcd.AddContact(Handle, nick, picture, "", unread, int(connections.ConnectionStateToType[contact.State]), contact.Blocked, false) } } -func (this *InterfaceState) AddSendMessageError(peer string, signature string, err string) { +func (this *Manager) AddSendMessageError(peer string, signature string, err string) { log.Debugf("Received Error Sending Message: %v", err) // FIXME: Sometimes, for the first Peer message we send our error beats our message to the UI time.Sleep(time.Second * 1) - this.parentGcd.GroupSendError(signature, err) + this.gcd.GroupSendError(signature, err) } -func (this *InterfaceState) AddMessage(m *gobjects.Message) { - updateLastReadTime(m.Handle) +func (this *Manager) AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool) { + updateLastReadTime(handle) + + nick := getOrDefault(handle, constants.Nick, handle) + image := getProfilePic(handle) // If we have this group loaded already - if this.parentGcd.CurrentOpenConversation() == m.Handle { + if this.gcd.CurrentOpenConversation() == handle { // If the message is not from the user then add it, otherwise, just acknowledge. - if !m.FromMe || !m.Acknowledged { - this.parentGcd.AppendMessage(m.Handle, m.From, m.DisplayName, m.Message, m.Image, m.MessageID, m.FromMe, m.Timestamp.Format(constants.TIME_FORMAT), m.Acknowledged, m.Error) + if !fromMe { + this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Format(constants.TIME_FORMAT), false, false) } else { - this.parentGcd.Acknowledged(m.MessageID) + if !Acknowledged { + this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Format(constants.TIME_FORMAT), false, false) + } else { + this.gcd.Acknowledged(messageID) + } } } else { - this.parentGcd.IncContactUnreadCount(m.Handle) + this.gcd.IncContactUnreadCount(handle) } } -func (this *InterfaceState) UpdateContactDisplayName(handle string, name string) { - this.parentGcd.UpdateContactDisplayName(handle, name) +func (this *Manager) UpdateContactDisplayName(handle string, name string) { + this.gcd.UpdateContactDisplayName(handle, name) } -func (this *InterfaceState) UpdateContactStatus(handle string, status int, loading bool) { - this.parentGcd.UpdateContactStatus(handle, status, loading) +func (this *Manager) UpdateContactStatus(handle string, status int, loading bool) { + this.gcd.UpdateContactStatus(handle, status, loading) } -func (this *InterfaceState) UpdateContactAttribute(handle, key, value string) { - this.parentGcd.UpdateContactAttribute(handle, key, value) +func (this *Manager) UpdateContactAttribute(handle, key, value string) { + this.gcd.UpdateContactAttribute(handle, key, value) } diff --git a/go/cwutil/utils.go b/go/ui/utils.go similarity index 99% rename from go/cwutil/utils.go rename to go/ui/utils.go index e3f6490a..6b382d4b 100644 --- a/go/cwutil/utils.go +++ b/go/ui/utils.go @@ -1,4 +1,4 @@ -package cwutil +package ui import ( "encoding/base32" diff --git a/main.go b/main.go index 2c7e3320..1b514f52 100644 --- a/main.go +++ b/main.go @@ -3,10 +3,10 @@ package main import ( libapp "cwtch.im/cwtch/app" "cwtch.im/cwtch/event/bridge" - "cwtch.im/ui/go/characters" - "cwtch.im/ui/go/gothings" - "cwtch.im/ui/go/gothings/android" + "cwtch.im/ui/go/handlers" "cwtch.im/ui/go/the" + "cwtch.im/ui/go/ui" + "cwtch.im/ui/go/ui/android" "flag" "git.openprivacy.ca/openprivacy/libricochet-go/connectivity" "git.openprivacy.ca/openprivacy/libricochet-go/log" @@ -32,7 +32,7 @@ var ( func init() { // make go-defined types available in qml - gothings.GrandCentralDispatcher_QmlRegisterType2("CustomQmlTypes", 1, 0, "GrandCentralDispatcher") + ui.GrandCentralDispatcher_QmlRegisterType2("CustomQmlTypes", 1, 0, "GrandCentralDispatcher") } func main() { @@ -128,7 +128,7 @@ func mainUi(flagLocal bool, flagClientUI bool) { app := gui.NewQGuiApplication(len(os.Args), os.Args) // our globals - gcd := gothings.NewGrandCentralDispatcher(nil) + gcd := ui.NewGrandCentralDispatcher(nil) gcd.SetOs(runtime.GOOS) if buildVer != "" { gcd.SetVersion(buildVer) @@ -137,7 +137,7 @@ func mainUi(flagLocal bool, flagClientUI bool) { gcd.SetVersion("development") gcd.SetBuildDate("now") } - gcd.UIState = gothings.NewUIState(gcd) + gcd.UIManager = ui.NewManager(gcd) //TODO: put theme stuff somewhere better gcd.SetThemeScale(1.0) @@ -232,7 +232,7 @@ func loadACN() { } } -func loadNetworkingAndFiles(gcd *gothings.GrandCentralDispatcher, service bool, clientUI bool) { +func loadNetworkingAndFiles(gcd *ui.GrandCentralDispatcher, service bool, clientUI bool) { if service || clientUI || runtime.GOOS == "android" { clientIn := path.Join(the.CwtchDir, "clientIn") serviceIn := path.Join(the.CwtchDir, "serviceIn") @@ -255,7 +255,7 @@ func loadNetworkingAndFiles(gcd *gothings.GrandCentralDispatcher, service bool, if !service { the.AppBus = the.CwtchApp.GetPrimaryBus() subscribed := make(chan bool) - go characters.AppEventListener(gcd, subscribed) + go handlers.App(gcd, subscribed) <-subscribed }