Merge branch 'master' of git.openprivacy.ca:cwtch.im/ui
This commit is contained in:
commit
3c6350944c
|
@ -29,8 +29,9 @@ func CwtchListener(callback func(message *gobjects.Message), groupID string, cha
|
||||||
m.Message,
|
m.Message,
|
||||||
"",
|
"",
|
||||||
m.PeerID == the.Peer.GetProfile().Onion,
|
m.PeerID == the.Peer.GetProfile().Onion,
|
||||||
0,
|
"0",
|
||||||
m.Timestamp,
|
m.Timestamp,
|
||||||
|
false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,12 +41,14 @@ func IncomingListener(callback func(*gobjects.Message)) {
|
||||||
case event.NewMessageFromGroup://event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
|
case event.NewMessageFromGroup://event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
|
||||||
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent])
|
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent])
|
||||||
callback(&gobjects.Message{
|
callback(&gobjects.Message{
|
||||||
|
MessageID: e.Data[event.Signature],
|
||||||
Handle: e.Data[event.GroupID],
|
Handle: e.Data[event.GroupID],
|
||||||
From: e.Data[event.RemotePeer],
|
From: e.Data[event.RemotePeer],
|
||||||
Message: e.Data[event.Data],
|
Message: e.Data[event.Data],
|
||||||
Image: cwutil.RandomProfileImage(e.Data[event.RemotePeer]),
|
Image: cwutil.RandomProfileImage(e.Data[event.RemotePeer]),
|
||||||
FromMe: e.Data[event.RemotePeer] == the.Peer.GetProfile().Onion,
|
FromMe: e.Data[event.RemotePeer] == the.Peer.GetProfile().Onion,
|
||||||
Timestamp: ts,
|
Timestamp: ts,
|
||||||
|
Acknowledged: true,
|
||||||
})
|
})
|
||||||
case event.NewGroupInvite:
|
case event.NewGroupInvite:
|
||||||
log.Debugf("got a group invite!")
|
log.Debugf("got a group invite!")
|
||||||
|
|
|
@ -3,5 +3,5 @@ package gobjects
|
||||||
// a Letter is a very simple message object passed to us from the UI
|
// a Letter is a very simple message object passed to us from the UI
|
||||||
type Letter struct {
|
type Letter struct {
|
||||||
To, Message string
|
To, Message string
|
||||||
MID uint
|
MID string
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ type Message struct {
|
||||||
Message string
|
Message string
|
||||||
Image string
|
Image string
|
||||||
FromMe bool
|
FromMe bool
|
||||||
MessageID int
|
MessageID string
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
|
Acknowledged bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,11 @@ import (
|
||||||
"cwtch.im/ui/go/constants"
|
"cwtch.im/ui/go/constants"
|
||||||
"cwtch.im/ui/go/cwutil"
|
"cwtch.im/ui/go/cwutil"
|
||||||
|
|
||||||
"cwtch.im/cwtch/model"
|
|
||||||
"cwtch.im/ui/go/characters"
|
|
||||||
"cwtch.im/ui/go/gobjects"
|
"cwtch.im/ui/go/gobjects"
|
||||||
"cwtch.im/ui/go/the"
|
"cwtch.im/ui/go/the"
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
"github.com/therecipe/qt/core"
|
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
||||||
|
"github.com/therecipe/qt/core"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -31,10 +29,10 @@ type GrandCentralDispatcher struct {
|
||||||
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
|
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
|
||||||
|
|
||||||
// messages pane stuff
|
// 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:"ClearMessages"`
|
||||||
_ func() `signal:"ResetMessagePane"`
|
_ func() `signal:"ResetMessagePane"`
|
||||||
_ func(mID uint) `signal:"Acknowledged"`
|
_ func(mID string) `signal:"Acknowledged"`
|
||||||
_ func(title string) `signal:"SetToolbarTitle"`
|
_ func(title string) `signal:"SetToolbarTitle"`
|
||||||
|
|
||||||
// profile-area stuff
|
// profile-area stuff
|
||||||
|
@ -47,7 +45,7 @@ type GrandCentralDispatcher struct {
|
||||||
_ func(onion, nick string) `signal:"SupplyPeerSettings"`
|
_ func(onion, nick string) `signal:"SupplyPeerSettings"`
|
||||||
|
|
||||||
// signals emitted from the ui (written in go, below)
|
// 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(onion string) `signal:"loadMessagesPane,auto"`
|
||||||
_ func(signal string) `signal:"broadcast,auto"` // convenience relay signal
|
_ func(signal string) `signal:"broadcast,auto"` // convenience relay signal
|
||||||
_ func(str string) `signal:"importString,auto"`
|
_ func(str string) `signal:"importString,auto"`
|
||||||
|
@ -64,7 +62,7 @@ type GrandCentralDispatcher struct {
|
||||||
_ func(onion, key, nick string) `signal:"setAttribute,auto"`
|
_ 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 {
|
if len(message) > 65530 {
|
||||||
this.InvokePopup("message is too long")
|
this.InvokePopup("message is too long")
|
||||||
return
|
return
|
||||||
|
@ -87,20 +85,25 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID uint) {
|
||||||
this.UIState.UpdateContact(c.Handle)
|
this.UIState.UpdateContact(c.Handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
the.Peer.SendMessageToGroup(this.CurrentOpenConversation(), message)
|
var err error
|
||||||
return
|
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
|
// TODO: require explicit invite accept/reject instead of implicitly trusting on send
|
||||||
if !this.UIState.GetContact(this.CurrentOpenConversation()).Trusted {
|
if !this.UIState.GetContact(this.CurrentOpenConversation()).Trusted {
|
||||||
this.UIState.GetContact(this.CurrentOpenConversation()).Trusted = true
|
this.UIState.GetContact(this.CurrentOpenConversation()).Trusted = true
|
||||||
this.UIState.UpdateContact(this.CurrentOpenConversation())
|
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
|
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
|
// 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}:
|
case this.OutgoingMessages <- gobjects.Letter{this.CurrentOpenConversation(), message, mID}:
|
||||||
default:
|
default:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.UIState.AddMessage(&gobjects.Message{
|
this.UIState.AddMessage(&gobjects.Message{
|
||||||
|
@ -110,8 +113,9 @@ func (this *GrandCentralDispatcher) sendMessage(message string, mID uint) {
|
||||||
message,
|
message,
|
||||||
"",
|
"",
|
||||||
true,
|
true,
|
||||||
int(mID),
|
mID,
|
||||||
time.Now(),
|
time.Now(),
|
||||||
|
false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,9 +178,10 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
||||||
name,
|
name,
|
||||||
tl[i].Message,
|
tl[i].Message,
|
||||||
cwutil.RandomProfileImage(tl[i].PeerID),
|
cwutil.RandomProfileImage(tl[i].PeerID),
|
||||||
0,
|
string(tl[i].Signature),
|
||||||
tl[i].PeerID == the.Peer.GetProfile().Onion,
|
tl[i].PeerID == the.Peer.GetProfile().Onion,
|
||||||
tl[i].Timestamp.Format(constants.TIME_FORMAT),
|
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
|
return
|
||||||
|
@ -204,12 +209,13 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
||||||
messages[i].DisplayName,
|
messages[i].DisplayName,
|
||||||
messages[i].Message,
|
messages[i].Message,
|
||||||
cwutil.RandomProfileImage(handle),
|
cwutil.RandomProfileImage(handle),
|
||||||
uint(messages[i].MessageID),
|
messages[i].MessageID,
|
||||||
messages[i].FromMe,
|
messages[i].FromMe,
|
||||||
messages[i].Timestamp.Format(constants.TIME_FORMAT),
|
messages[i].Timestamp.Format(constants.TIME_FORMAT),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
for _,id := range the.AcknowledgementIDs[messages[i].Handle] {
|
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)
|
this.Acknowledged(id.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -412,8 +418,6 @@ func (this *GrandCentralDispatcher) createGroup(server, groupName string) {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
the.Peer.JoinServer(server)
|
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) {
|
func (this *GrandCentralDispatcher) inviteToGroup(onion, groupID string) {
|
||||||
|
|
|
@ -94,6 +94,11 @@ func (this *InterfaceState) AddMessage(m *gobjects.Message) {
|
||||||
this.messages[m.Handle] = make([]*gobjects.Message, 0)
|
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 m.Message == "ack" {
|
||||||
// If an ack, swallow the message and ack from the list.
|
// If an ack, swallow the message and ack from the list.
|
||||||
acklist := the.AcknowledgementIDs[m.From]
|
acklist := the.AcknowledgementIDs[m.From]
|
||||||
|
@ -104,8 +109,14 @@ func (this *InterfaceState) AddMessage(m *gobjects.Message) {
|
||||||
} else {
|
} else {
|
||||||
this.messages[m.Handle] = append(this.messages[m.Handle], m)
|
this.messages[m.Handle] = append(this.messages[m.Handle], m)
|
||||||
|
|
||||||
|
// If we have this group loaded already
|
||||||
if this.parentGcd.CurrentOpenConversation() == m.Handle {
|
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 {
|
} else {
|
||||||
c := this.GetContact(m.Handle)
|
c := this.GetContact(m.Handle)
|
||||||
if c != nil {
|
if c != nil {
|
||||||
|
|
|
@ -10,7 +10,7 @@ var Peer libPeer.CwtchPeer
|
||||||
var CwtchDir string
|
var CwtchDir string
|
||||||
|
|
||||||
type AckId struct {
|
type AckId struct {
|
||||||
ID uint
|
ID string
|
||||||
Ack bool
|
Ack bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ ColumnLayout {
|
||||||
txtMessage.text = ""
|
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
|
var msg
|
||||||
try {
|
try {
|
||||||
msg = JSON.parse(message)
|
msg = JSON.parse(message)
|
||||||
|
@ -41,6 +41,7 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
if (msg.o != 1) return
|
if (msg.o != 1) return
|
||||||
|
|
||||||
|
|
||||||
messagesModel.append({
|
messagesModel.append({
|
||||||
"_handle": handle,
|
"_handle": handle,
|
||||||
"_from": from,
|
"_from": from,
|
||||||
|
@ -50,8 +51,11 @@ ColumnLayout {
|
||||||
"_mid": mid,
|
"_mid": mid,
|
||||||
"_fromMe": fromMe,
|
"_fromMe": fromMe,
|
||||||
"_ts": ts,
|
"_ts": ts,
|
||||||
|
"_ackd": ackd,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// If the window is out of focus, alert the user (makes taskbar light up)
|
// If the window is out of focus, alert the user (makes taskbar light up)
|
||||||
windowItem.alert(0)
|
windowItem.alert(0)
|
||||||
|
|
||||||
|
@ -88,6 +92,7 @@ ColumnLayout {
|
||||||
messageID: _mid
|
messageID: _mid
|
||||||
fromMe: _fromMe
|
fromMe: _fromMe
|
||||||
timestamp: _ts
|
timestamp: _ts
|
||||||
|
ackd: _ackd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,9 @@ RowLayout {
|
||||||
property string from
|
property string from
|
||||||
property string handle
|
property string handle
|
||||||
property string displayName
|
property string displayName
|
||||||
property int messageID
|
property string messageID
|
||||||
property bool fromMe
|
property bool fromMe
|
||||||
|
property bool ackd
|
||||||
property alias timestamp: ts.text
|
property alias timestamp: ts.text
|
||||||
property alias image: imgProfile.source
|
property alias image: imgProfile.source
|
||||||
property alias status: imgProfile.status
|
property alias status: imgProfile.status
|
||||||
|
@ -28,7 +29,7 @@ RowLayout {
|
||||||
|
|
||||||
onAcknowledged: function(mid) {
|
onAcknowledged: function(mid) {
|
||||||
if (mid == messageID) {
|
if (mid == messageID) {
|
||||||
ack.source = "qrc:/qml/images/fontawesome/regular/check-circle.svg"
|
root.ackd = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ RowLayout {
|
||||||
Image { // ACKNOWLEDGEMENT ICON
|
Image { // ACKNOWLEDGEMENT ICON
|
||||||
id: ack
|
id: ack
|
||||||
anchors.right: parent.right
|
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
|
height: 10
|
||||||
sourceSize.height: 10
|
sourceSize.height: 10
|
||||||
visible: fromMe
|
visible: fromMe
|
||||||
|
|
Reference in New Issue