Add Status Indicators for Group Messages

This commit is contained in:
Sarah Jamie Lewis 2019-02-20 12:07:12 -08:00
parent 1483492f61
commit 6e50004402
9 changed files with 59 additions and 34 deletions

View File

@ -29,8 +29,9 @@ func CwtchListener(callback func(message *gobjects.Message), groupID string, cha
m.Message,
"",
m.PeerID == the.Peer.GetProfile().Onion,
0,
"0",
m.Timestamp,
false,
})
}
}

View File

@ -41,12 +41,14 @@ func IncomingListener(callback func(*gobjects.Message)) {
case event.NewMessageFromGroup://event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent])
callback(&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,
})
case event.NewGroupInvite:
log.Debugf("got a group invite!")

View File

@ -3,5 +3,5 @@ package gobjects
// a Letter is a very simple message object passed to us from the UI
type Letter struct {
To, Message string
MID uint
MID string
}

View File

@ -9,6 +9,7 @@ type Message struct {
Message string
Image string
FromMe bool
MessageID int
MessageID string
Timestamp time.Time
Acknowledged bool
}

View File

@ -5,13 +5,11 @@ import (
"cwtch.im/ui/go/constants"
"cwtch.im/ui/go/cwutil"
"cwtch.im/cwtch/model"
"cwtch.im/ui/go/characters"
"cwtch.im/ui/go/gobjects"
"cwtch.im/ui/go/the"
"encoding/base32"
"github.com/therecipe/qt/core"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"github.com/therecipe/qt/core"
"strings"
"time"
)
@ -31,10 +29,10 @@ type GrandCentralDispatcher struct {
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
// messages pane stuff
_ func(handle, from, displayName, message, image string, mID uint, fromMe bool, ts string) `signal:"AppendMessage"`
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts string, ackd bool) `signal:"AppendMessage"`
_ func() `signal:"ClearMessages"`
_ func() `signal:"ResetMessagePane"`
_ func(mID uint) `signal:"Acknowledged"`
_ func(mID string) `signal:"Acknowledged"`
_ func(title string) `signal:"SetToolbarTitle"`
// profile-area stuff
@ -47,7 +45,7 @@ type GrandCentralDispatcher struct {
_ func(onion, nick string) `signal:"SupplyPeerSettings"`
// signals emitted from the ui (written in go, below)
_ func(message string, mid uint) `signal:"sendMessage,auto"`
_ func(message string, mid string) `signal:"sendMessage,auto"`
_ func(onion string) `signal:"loadMessagesPane,auto"`
_ func(signal string) `signal:"broadcast,auto"` // convenience relay signal
_ func(str string) `signal:"importString,auto"`
@ -64,7 +62,7 @@ type GrandCentralDispatcher struct {
_ func(onion, key, nick string) `signal:"setAttribute,auto"`
}
func (this *GrandCentralDispatcher) sendMessage(message string, mID uint) {
func (this *GrandCentralDispatcher) sendMessage(message string, mID string) {
if len(message) > 65530 {
this.InvokePopup("message is too long")
return
@ -87,20 +85,25 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID uint) {
this.UIState.UpdateContact(c.Handle)
}
the.Peer.SendMessageToGroup(this.CurrentOpenConversation(), message)
return
}
var err error
mID,err = the.Peer.SendMessageToGroupTracked(this.CurrentOpenConversation(), message)
if err != nil {
this.InvokePopup("failed to send message " +err.Error())
return
}
} else {
// TODO: require explicit invite accept/reject instead of implicitly trusting on send
if !this.UIState.GetContact(this.CurrentOpenConversation()).Trusted {
this.UIState.GetContact(this.CurrentOpenConversation()).Trusted = true
this.UIState.UpdateContact(this.CurrentOpenConversation())
}
// TODO: require explicit invite accept/reject instead of implicitly trusting on send
if !this.UIState.GetContact(this.CurrentOpenConversation()).Trusted {
this.UIState.GetContact(this.CurrentOpenConversation()).Trusted = true
this.UIState.UpdateContact(this.CurrentOpenConversation())
}
select { // 1 weird trick to do a non-blocking send. this means the user can only send a limited number of messages
// before the channel buffer fills. TODO: stop the user from sending if the buffer is full
case this.OutgoingMessages <- gobjects.Letter{this.CurrentOpenConversation(), message, mID}:
default:
select { // 1 weird trick to do a non-blocking send. this means the user can only send a limited number of messages
// before the channel buffer fills. TODO: stop the user from sending if the buffer is full
case this.OutgoingMessages <- gobjects.Letter{this.CurrentOpenConversation(), message, mID}:
default:
}
}
this.UIState.AddMessage(&gobjects.Message{
@ -110,8 +113,9 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID uint) {
message,
"",
true,
int(mID),
mID,
time.Now(),
false,
})
}
@ -174,9 +178,10 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
name,
tl[i].Message,
cwutil.RandomProfileImage(tl[i].PeerID),
0,
string(tl[i].Signature),
tl[i].PeerID == the.Peer.GetProfile().Onion,
tl[i].Timestamp.Format(constants.TIME_FORMAT),
tl[i].Received.Equal(time.Unix(0,0)) == false, // If the received timestamp is epoch, we have not yet received this message through an active server
)
}
return
@ -204,12 +209,13 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
messages[i].DisplayName,
messages[i].Message,
cwutil.RandomProfileImage(handle),
uint(messages[i].MessageID),
messages[i].MessageID,
messages[i].FromMe,
messages[i].Timestamp.Format(constants.TIME_FORMAT),
true,
)
for _,id := range the.AcknowledgementIDs[messages[i].Handle] {
if int(id.ID) == messages[i].MessageID && id.Ack{
if id.ID == messages[i].MessageID && id.Ack{
this.Acknowledged(id.ID)
}
}
@ -412,8 +418,6 @@ func (this *GrandCentralDispatcher) createGroup(server, groupName string) {
}))
the.Peer.JoinServer(server)
group.NewMessage = make(chan model.Message)
go characters.CwtchListener(this.UIState.AddMessage, group.GroupID, group.NewMessage)
}
func (this *GrandCentralDispatcher) inviteToGroup(onion, groupID string) {

View File

@ -94,6 +94,11 @@ func (this *InterfaceState) AddMessage(m *gobjects.Message) {
this.messages[m.Handle] = make([]*gobjects.Message, 0)
}
// Ack message sent to group
this.parentGcd.Acknowledged(m.MessageID)
// Ack personal messages
// TODO: unify this with the above signature based approach
if m.Message == "ack" {
// If an ack, swallow the message and ack from the list.
acklist := the.AcknowledgementIDs[m.From]
@ -104,8 +109,14 @@ func (this *InterfaceState) AddMessage(m *gobjects.Message) {
} else {
this.messages[m.Handle] = append(this.messages[m.Handle], m)
// If we have this group loaded already
if this.parentGcd.CurrentOpenConversation() == m.Handle {
this.parentGcd.AppendMessage(m.Handle, m.From, m.DisplayName, m.Message, m.Image, uint(m.MessageID), m.FromMe, m.Timestamp.Format(constants.TIME_FORMAT))
// 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)
} else {
this.parentGcd.Acknowledged(m.MessageID)
}
} else {
c := this.GetContact(m.Handle)
if c != nil {

View File

@ -10,7 +10,7 @@ var Peer libPeer.CwtchPeer
var CwtchDir string
type AckId struct {
ID uint
ID string
Ack bool
}

View File

@ -32,7 +32,7 @@ ColumnLayout {
txtMessage.text = ""
}
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts) {
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ackd) {
var msg
try {
msg = JSON.parse(message)
@ -41,6 +41,7 @@ ColumnLayout {
}
if (msg.o != 1) return
messagesModel.append({
"_handle": handle,
"_from": from,
@ -50,8 +51,11 @@ ColumnLayout {
"_mid": mid,
"_fromMe": fromMe,
"_ts": ts,
"_ackd": ackd,
})
// If the window is out of focus, alert the user (makes taskbar light up)
windowItem.alert(0)
@ -88,6 +92,7 @@ ColumnLayout {
messageID: _mid
fromMe: _fromMe
timestamp: _ts
ackd: _ackd
}
}
}

View File

@ -17,8 +17,9 @@ RowLayout {
property string from
property string handle
property string displayName
property int messageID
property string messageID
property bool fromMe
property bool ackd
property alias timestamp: ts.text
property alias image: imgProfile.source
property alias status: imgProfile.status
@ -28,7 +29,7 @@ RowLayout {
onAcknowledged: function(mid) {
if (mid == messageID) {
ack.source = "qrc:/qml/images/fontawesome/regular/check-circle.svg"
root.ackd = true
}
}
@ -129,7 +130,7 @@ RowLayout {
Image { // ACKNOWLEDGEMENT ICON
id: ack
anchors.right: parent.right
source: from == "me" ? "qrc:/qml/images/fontawesome/regular/hourglass.svg" : "qrc:/qml/images/fontawesome/regular/check-circle.svg"
source: root.ackd ? "qrc:/qml/images/fontawesome/regular/check-circle.svg" : "qrc:/qml/images/fontawesome/regular/hourglass.svg"
height: 10
sourceSize.height: 10
visible: fromMe