finishing first attempt at message model pr. mainly group acks
This commit is contained in:
parent
7bb2198879
commit
e09ad91ab5
|
@ -10,6 +10,7 @@ import (
|
|||
"cwtch.im/ui/go/constants"
|
||||
"cwtch.im/ui/go/the"
|
||||
"cwtch.im/ui/go/ui"
|
||||
"encoding/hex"
|
||||
"git.openprivacy.ca/openprivacy/log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
@ -54,19 +55,15 @@ func PeerHandler(onion string, uiManager ui.Manager, subscribed chan bool) {
|
|||
|
||||
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
|
||||
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampReceived])
|
||||
//uiManager.AddMessage(e.Data[event.RemotePeer], e.Data[event.RemotePeer], e.Data[event.Data], false, e.EventID, ts, true)
|
||||
uiManager.AboutToAddMessage()
|
||||
//time.Sleep(time.Millisecond)
|
||||
peer.StoreMessage(e.Data[event.RemotePeer], e.Data[event.Data], ts)
|
||||
uiManager.MessageJustAdded()
|
||||
|
||||
uiManager.StoreAndNotify(peer, e.Data[event.RemotePeer], e.Data[event.Data], ts, onion)
|
||||
|
||||
case event.PeerAcknowledgement:
|
||||
uiManager.Acknowledge(e.Data[event.EventID])
|
||||
uiManager.Acknowledge(e.Data[event.RemotePeer], e.Data[event.EventID])
|
||||
|
||||
case event.NewMessageFromGroup: //event.TimestampReceived, event.TimestampSent, event.Data, event.GroupID, event.RemotePeer
|
||||
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampSent])
|
||||
uiManager.AddMessage(e.Data[event.GroupID], e.Data[event.RemotePeer], e.Data[event.Data], e.Data[event.RemotePeer] == peer.GetOnion(), e.Data[event.Signature], ts, true)
|
||||
uiManager.AddMessage(e.Data[event.GroupID], e.Data[event.RemotePeer], e.Data[event.Data], e.Data[event.RemotePeer] == peer.GetOnion(), hex.EncodeToString([]byte(e.Data[event.Signature])), ts, true)
|
||||
|
||||
case event.NewGroupInvite:
|
||||
gid, err := peer.ProcessInvite(e.Data[event.GroupInvite], e.Data[event.RemotePeer])
|
||||
group := peer.GetGroup(gid)
|
||||
|
|
109
go/ui/gcd.go
109
go/ui/gcd.go
|
@ -2,6 +2,7 @@ package ui
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"cwtch.im/cwtch/app"
|
||||
|
@ -12,13 +13,11 @@ import (
|
|||
"cwtch.im/ui/go/constants"
|
||||
"github.com/therecipe/qt/qml"
|
||||
|
||||
"encoding/base32"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"cwtch.im/ui/go/the"
|
||||
"encoding/base32"
|
||||
"git.openprivacy.ca/openprivacy/log"
|
||||
"github.com/therecipe/qt/core"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type GrandCentralDispatcher struct {
|
||||
|
@ -66,8 +65,6 @@ type GrandCentralDispatcher struct {
|
|||
_ func(handle, key, value string) `signal:"UpdateContactAttribute"`
|
||||
|
||||
// messages pane stuff
|
||||
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts int64, ackd bool, error bool) `signal:"AppendMessage"`
|
||||
_ func(handle, from, displayName, message, image string, mID string, fromMe bool, ts int64, ackd bool, error bool) `signal:"PrependMessage"`
|
||||
_ func() `signal:"ClearMessages"`
|
||||
_ func() `signal:"ResetMessagePane"`
|
||||
_ func(mID string) `signal:"Acknowledged"`
|
||||
|
@ -120,6 +117,8 @@ type GrandCentralDispatcher struct {
|
|||
_ func() `signal:"blockUnknownPeers,auto"`
|
||||
_ func(onion string) `signal:"storeHistoryForPeer,auto"`
|
||||
_ func(onion string) `signal:"deleteHistoryForPeer,auto"`
|
||||
// chat
|
||||
_ func(mID string) `slot:"acktest,auto"`
|
||||
|
||||
_ func(handle string) `signal:"requestServerSettings,auto"`
|
||||
|
||||
|
@ -175,6 +174,18 @@ func (this *GrandCentralDispatcher) DoIfProfile(profile string, fn func()) {
|
|||
}
|
||||
}
|
||||
|
||||
// Like DoIfProfile() but runs elseFn() if profile isn't the currently selected one in the UI
|
||||
func (this *GrandCentralDispatcher) DoIfProfileElse(profile string, fn func(), elseFn func()) {
|
||||
this.profileLock.Lock()
|
||||
defer this.profileLock.Unlock()
|
||||
|
||||
if this.m_selectedProfile == profile {
|
||||
fn()
|
||||
} else {
|
||||
elseFn()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *GrandCentralDispatcher) selectedConversation() string {
|
||||
this.conversationLock.Lock()
|
||||
defer this.conversationLock.Unlock()
|
||||
|
@ -204,6 +215,18 @@ func (this *GrandCentralDispatcher) DoIfConversation(conversation string, fn fun
|
|||
}
|
||||
}
|
||||
|
||||
// like DoIfConversation() but
|
||||
func (this *GrandCentralDispatcher) DoIfConversationElse(conversation string, fn func(), elseFn func()) {
|
||||
this.conversationLock.Lock()
|
||||
defer this.conversationLock.Unlock()
|
||||
|
||||
if this.m_selectedConversation == conversation {
|
||||
fn()
|
||||
} else {
|
||||
elseFn()
|
||||
}
|
||||
}
|
||||
|
||||
func (this *GrandCentralDispatcher) sendMessage(message string) {
|
||||
if len(message) > 65530 {
|
||||
this.InvokePopup("message is too long")
|
||||
|
@ -224,22 +247,18 @@ func (this *GrandCentralDispatcher) sendMessage(message string) {
|
|||
}
|
||||
}
|
||||
|
||||
mID, err := the.Peer.SendMessageToGroupTracked(this.SelectedConversation(), message)
|
||||
|
||||
this.GetUiManager(this.selectedProfile()).AddMessage(this.SelectedConversation(), "me", message, true, mID, time.Now(), false)
|
||||
this.TimelineInterface.AddMessage(this.TimelineInterface.num())
|
||||
_, err := the.Peer.SendMessageToGroupTracked(this.SelectedConversation(), message)
|
||||
this.TimelineInterface.RequestEIR()
|
||||
|
||||
if err != nil {
|
||||
this.InvokePopup("failed to send message " + err.Error())
|
||||
return
|
||||
}
|
||||
} else {
|
||||
to := this.SelectedConversation()
|
||||
prenum := this.TimelineInterface.num()
|
||||
this.TimelineInterface.AddMessage(prenum)
|
||||
/*mID := */the.Peer.SendMessageToPeer(to, message)
|
||||
this.TimelineInterface.AddMessage(this.TimelineInterface.num())
|
||||
the.Peer.SendMessageToPeer(this.SelectedConversation(), message)
|
||||
this.TimelineInterface.RequestEIR()
|
||||
|
||||
//this.GetUiManager(this.selectedProfile()).AddMessage(to, "me", message, true, mID, time.Now(), false)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -266,7 +285,6 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
|||
this.UpdateContactStatus(group.GroupID, int(state), loading)
|
||||
this.requestGroupSettings(handle)
|
||||
|
||||
tl := group.GetTimeline()
|
||||
nick := GetNick(handle)
|
||||
updateLastReadTime(group.GroupID)
|
||||
if nick == "" {
|
||||
|
@ -275,34 +293,6 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
|||
this.SetToolbarTitle(nick)
|
||||
}
|
||||
|
||||
go func() {
|
||||
// Janky hack to let the ui/qml respond to the status updates first before freezing under a deluge of new messages
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
for i := len(tl) - 1; i >= 0; i-- {
|
||||
if tl[i].PeerID == the.Peer.GetOnion() {
|
||||
handle = "me"
|
||||
} else {
|
||||
handle = tl[i].PeerID
|
||||
}
|
||||
|
||||
name := GetNick(tl[i].PeerID)
|
||||
image := GetProfilePic(tl[i].PeerID)
|
||||
|
||||
this.PrependMessage(
|
||||
handle,
|
||||
tl[i].PeerID,
|
||||
name,
|
||||
tl[i].Message,
|
||||
image,
|
||||
string(tl[i].Signature),
|
||||
tl[i].PeerID == the.Peer.GetOnion(),
|
||||
tl[i].Timestamp.Unix(),
|
||||
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
|
||||
false,
|
||||
)
|
||||
}
|
||||
}()
|
||||
|
||||
return
|
||||
} // ELSE LOAD CONTACT
|
||||
|
||||
|
@ -317,32 +307,6 @@ func (this *GrandCentralDispatcher) loadMessagesPaneHelper(handle string) {
|
|||
}
|
||||
updateLastReadTime(contact.Onion)
|
||||
this.SetToolbarTitle(nick)
|
||||
|
||||
peer := the.Peer.GetContact(handle)
|
||||
messages := peer.Timeline.GetMessages()
|
||||
for i := range messages {
|
||||
from := messages[i].PeerID
|
||||
fromMe := messages[i].PeerID == the.Peer.GetOnion()
|
||||
if fromMe {
|
||||
from = "me"
|
||||
}
|
||||
|
||||
displayname := GetNick(messages[i].PeerID)
|
||||
image := GetProfilePic(messages[i].PeerID)
|
||||
|
||||
this.AppendMessage(
|
||||
from,
|
||||
messages[i].PeerID,
|
||||
displayname,
|
||||
messages[i].Message,
|
||||
image,
|
||||
string(messages[i].Signature),
|
||||
fromMe,
|
||||
messages[i].Timestamp.Unix(),
|
||||
messages[i].Acknowledged,
|
||||
messages[i].Error != "",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *GrandCentralDispatcher) requestSettings() {
|
||||
|
@ -760,3 +724,8 @@ func (this *GrandCentralDispatcher) deleteProfile(onion string) {
|
|||
log.Infof("deleteProfile %v\n", onion)
|
||||
the.CwtchApp.DeletePeer(onion)
|
||||
}
|
||||
|
||||
func (this *GrandCentralDispatcher) acktest(mID string) {
|
||||
idx, _ := strconv.Atoi(mID)
|
||||
this.TimelineInterface.EditMessage(idx)
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"cwtch.im/cwtch/app"
|
||||
"cwtch.im/cwtch/model"
|
||||
"cwtch.im/cwtch/model/attr"
|
||||
"cwtch.im/cwtch/peer"
|
||||
"cwtch.im/cwtch/protocol/connections"
|
||||
"cwtch.im/ui/go/constants"
|
||||
"cwtch.im/ui/go/the"
|
||||
|
@ -202,7 +203,7 @@ type manager struct {
|
|||
// manager also performs call filtering based on UI state: users of manager can safely always call it on events and not have to worry about weather the relevant ui is active
|
||||
// ie: you can always safely call AddMessage even if in the ui a different profile is selected. manager will check with gcd, and if the correct conditions are not met, it will not call on gcd to update the ui incorrectly
|
||||
type Manager interface {
|
||||
Acknowledge(mID string)
|
||||
Acknowledge(handle, mID string)
|
||||
AddContact(Handle string)
|
||||
AddSendMessageError(peer string, signature string, err string)
|
||||
AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool)
|
||||
|
@ -218,6 +219,7 @@ type Manager interface {
|
|||
|
||||
AboutToAddMessage()
|
||||
MessageJustAdded()
|
||||
StoreAndNotify(peer.CwtchPeer, string, string, time.Time, string)
|
||||
}
|
||||
|
||||
// NewManager returns a new Manager interface for a profile to the gcd
|
||||
|
@ -226,9 +228,11 @@ func NewManager(profile string, gcd *GrandCentralDispatcher) Manager {
|
|||
}
|
||||
|
||||
// Acknowledge acknowledges the given message id in the UI
|
||||
func (this *manager) Acknowledge(mID string) {
|
||||
func (this *manager) Acknowledge(handle, mID string) {
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
this.gcd.Acknowledged(mID)
|
||||
this.gcd.DoIfConversation(handle, func(){
|
||||
this.gcd.Acktest(mID)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -291,28 +295,34 @@ func (this *manager) MessageJustAdded() {
|
|||
this.gcd.TimelineInterface.RequestEIR()
|
||||
}
|
||||
|
||||
func (this *manager) StoreAndNotify(pere peer.CwtchPeer, onion string, messageTxt string, sent time.Time, profileOnion string) {
|
||||
this.gcd.DoIfProfileElse(this.profile, func() {
|
||||
this.gcd.DoIfConversationElse(onion, func() {
|
||||
updateLastReadTime(onion)
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num())
|
||||
pere.StoreMessage(onion, messageTxt, sent)
|
||||
this.gcd.TimelineInterface.RequestEIR()
|
||||
}, func() {
|
||||
updateLastReadTime(onion)
|
||||
pere.StoreMessage(onion, messageTxt, sent)
|
||||
})
|
||||
this.gcd.IncContactUnreadCount(onion)
|
||||
}, func() {
|
||||
the.CwtchApp.GetPeer(profileOnion).StoreMessage(onion, messageTxt, sent)
|
||||
})
|
||||
}
|
||||
|
||||
// AddMessage adds a message to the message pane for the supplied conversation if it is active
|
||||
func (this *manager) AddMessage(handle string, from string, message string, fromMe bool, messageID string, timestamp time.Time, Acknowledged bool) {
|
||||
log.Errorf("uiManager.AddMessage(...) uhhhh???? NO ZOOP ZEEP")
|
||||
this.gcd.DoIfProfile(this.profile, func() {
|
||||
|
||||
//nick := GetNick(handle)
|
||||
//image := GetProfilePic(handle)
|
||||
|
||||
// If we have this group loaded already
|
||||
this.gcd.DoIfConversation(handle, func() {
|
||||
updateLastReadTime(handle)
|
||||
// If the message is not from the user then add it, otherwise, just acknowledge.
|
||||
if !fromMe {
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num())
|
||||
//this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Unix(), false, false)
|
||||
if !fromMe || !Acknowledged {
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num()-1)
|
||||
this.gcd.TimelineInterface.RequestEIR()
|
||||
} else {
|
||||
if !Acknowledged {
|
||||
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num())
|
||||
//this.gcd.AppendMessage(handle, from, nick, message, image, messageID, fromMe, timestamp.Unix(), false, false)
|
||||
} else {
|
||||
this.gcd.Acknowledged(messageID)
|
||||
}
|
||||
this.gcd.Acknowledged(messageID)
|
||||
}
|
||||
})
|
||||
this.gcd.IncContactUnreadCount(handle)
|
||||
|
|
|
@ -3,6 +3,7 @@ package ui
|
|||
import (
|
||||
"cwtch.im/cwtch/model"
|
||||
"cwtch.im/ui/go/the"
|
||||
"encoding/hex"
|
||||
"git.openprivacy.ca/openprivacy/log"
|
||||
"github.com/therecipe/qt/core"
|
||||
"reflect"
|
||||
|
@ -12,16 +13,16 @@ import (
|
|||
type MessageModel struct {
|
||||
core.QAbstractTableModel
|
||||
|
||||
ackIdx int
|
||||
handle string
|
||||
//_ string `property:"handle,auto"`
|
||||
_ func(string) `signal:"setHandle,auto"`
|
||||
|
||||
_ map[int]*core.QByteArray `property:"roles"`
|
||||
_ func() `constructor:"init"`
|
||||
|
||||
_ func(int) `signal:"addMessage,auto"`
|
||||
_ func(string) `signal:"createLocalFormEntry,auto"`
|
||||
_ func() `signal:"requestEIR,auto"` // request this.EndInsertRecord() on gui thread
|
||||
_ func(int) `signal:"editMessage,auto"`
|
||||
_ func() `signal:"requestEIR,auto"`
|
||||
|
||||
_ func(string) string `slot:"getNick,auto"`
|
||||
_ func(string) string `slot:"getImage,auto"`
|
||||
|
@ -36,6 +37,8 @@ type MessageWrapper struct {
|
|||
Acknowledged bool
|
||||
RawMessage string
|
||||
Error string
|
||||
Day string
|
||||
Signature string
|
||||
_ bool `property:"ackd"`
|
||||
}
|
||||
|
||||
|
@ -49,10 +52,12 @@ func (this *MessageModel) setHandle(handle string) {
|
|||
|
||||
|
||||
func (this *MessageModel) init() {
|
||||
//mdt := reflect.TypeOf([]model.Message{}).Elem()
|
||||
mdt := reflect.TypeOf([]MessageWrapper{}).Elem()
|
||||
roles := make(map[int]*core.QByteArray)
|
||||
for i := 0; i < mdt.NumField(); i++ {
|
||||
if mdt.Field(i).Name == "Acknowledged" {
|
||||
this.ackIdx = int(core.Qt__UserRole) + 1 + i
|
||||
}
|
||||
roles[int(core.Qt__UserRole) + 1 + i] = core.NewQByteArray2(mdt.Field(i).Name, -1)
|
||||
}
|
||||
roles[int(core.Qt__DisplayRole)] = core.NewQByteArray2("display", -1)
|
||||
|
@ -83,7 +88,7 @@ func (this *MessageModel) getImage(handle string) string {
|
|||
|
||||
func (this *MessageModel) num() int {
|
||||
if this.Handle() == "" || the.Peer == nil {
|
||||
log.Debugf("num: early returning 0")
|
||||
log.Debugf("MessageModel.num: early returning 0")
|
||||
return 0
|
||||
}
|
||||
|
||||
|
@ -95,19 +100,17 @@ func (this *MessageModel) num() int {
|
|||
} else {
|
||||
contact := the.Peer.GetContact(this.Handle())
|
||||
if contact != nil {
|
||||
log.Debugf("num: returning %v", len(contact.Timeline.Messages))
|
||||
return len(contact.Timeline.Messages)
|
||||
}
|
||||
}
|
||||
|
||||
log.Warnf("group/contact was nil, returning 0")
|
||||
log.Warnf("MessageModel.num: group/contact was nil, returning 0")
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *MessageModel) getMessage(idx int) *MessageWrapper {
|
||||
log.Infof("MessageModel.getMessage(%v)", idx)
|
||||
|
||||
var modelmsg model.Message
|
||||
var ackd bool
|
||||
|
||||
if this.isGroup() {
|
||||
group := the.Peer.GetGroup(this.Handle())
|
||||
|
@ -115,6 +118,7 @@ func (this *MessageModel) getMessage(idx int) *MessageWrapper {
|
|||
modelmsg = group.UnacknowledgedMessages[idx - len(group.Timeline.Messages)]
|
||||
} else {
|
||||
modelmsg = group.Timeline.Messages[idx]
|
||||
ackd = true
|
||||
}
|
||||
} else {
|
||||
contact := the.Peer.GetContact(this.Handle())
|
||||
|
@ -122,9 +126,9 @@ func (this *MessageModel) getMessage(idx int) *MessageWrapper {
|
|||
modelmsg = model.Message{Message:"oops test hi uhhhhh :/"}
|
||||
} else if idx >= len(contact.Timeline.Messages) {
|
||||
log.Errorf("this shouldnt happen")
|
||||
//modelmsg = contact.UnacknowledgedMessages[idx-len(contact.Timeline.Messages)]
|
||||
} else {
|
||||
modelmsg = contact.Timeline.Messages[idx]
|
||||
ackd = modelmsg.Acknowledged
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,13 +138,13 @@ func (this *MessageModel) getMessage(idx int) *MessageWrapper {
|
|||
RawMessage: modelmsg.Message,
|
||||
PeerID: modelmsg.PeerID,
|
||||
Error: modelmsg.Error,
|
||||
Acknowledged: modelmsg.Acknowledged,
|
||||
Acknowledged: ackd,
|
||||
Day: modelmsg.Timestamp.Format("January 2, 2006"),
|
||||
Signature: hex.EncodeToString(modelmsg.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
func (this *MessageModel) data(index *core.QModelIndex, role int) *core.QVariant {
|
||||
log.Infof("MessageModel.data(%v, %v)", index.Row(), role)
|
||||
|
||||
if !index.IsValid() {
|
||||
return core.NewQVariant()
|
||||
}
|
||||
|
@ -173,7 +177,7 @@ func (this *MessageModel) headerData(section int, orientation core.Qt__Orientati
|
|||
return this.HeaderDataDefault(section, orientation, role)
|
||||
}
|
||||
|
||||
mdt := reflect.TypeOf([]model.Message{}).Elem()
|
||||
mdt := reflect.TypeOf([]MessageWrapper{}).Elem()
|
||||
return core.NewQVariant12(mdt.Field(section).Name)
|
||||
}
|
||||
|
||||
|
@ -185,30 +189,29 @@ func (this *MessageModel) columnCount(parent *core.QModelIndex) int {
|
|||
return reflect.TypeOf(MessageWrapper{}).NumField()
|
||||
}
|
||||
|
||||
// perform this.BeginInsertRows() on the gui thread
|
||||
// important:
|
||||
// 1. idx MUST be set to this.num()'s value *before* calling addMessage()
|
||||
// 2. insert the message yourself
|
||||
// 3. this.RequestEIR() *must* be called afterward
|
||||
func (this *MessageModel) addMessage(idx int) {
|
||||
log.Debugf("MessageModel.addMessage() ZOOP ZOOP %v", this.handle)
|
||||
this.BeginInsertRows(core.NewQModelIndex(), idx, idx)//this.num(), this.num())
|
||||
//this.modelData = append(this.modelData, *fe)
|
||||
//this.RequestEIR()
|
||||
this.BeginInsertRows(core.NewQModelIndex(), idx, idx)
|
||||
}
|
||||
|
||||
// perform this.EndInsertRows() on the gui thread
|
||||
// perform this.EndInsertRows() on the gui thread after an AddMessage()
|
||||
func (this *MessageModel) requestEIR() {
|
||||
log.Debugf("MessageModel.requestEIR() ZEEP ZEEP %v", this.handle)
|
||||
this.EndInsertRows()
|
||||
}
|
||||
|
||||
|
||||
func (this *MessageModel) createLocalFormEntry(name string) {
|
||||
go this.createLocalFormEntry_thread(name)
|
||||
}
|
||||
|
||||
func (this *MessageModel) createLocalFormEntry_thread(name string) {
|
||||
log.Debugf("nyi #9779729343959699492726648294050382")
|
||||
/*
|
||||
fe := &model.Message{
|
||||
Message: "hi!",
|
||||
// notify the gui that the message acknowledgement at index idx has been modified
|
||||
func (this *MessageModel) editMessage(idx int) {
|
||||
if idx < 0 || idx >= this.num() {
|
||||
log.Errorf("cant edit message %v. probably fine", idx)
|
||||
return
|
||||
}
|
||||
this.addMessage(fe)
|
||||
*/
|
||||
}
|
||||
|
||||
log.Debugf("editMessage(%v, %v)", idx, this.ackIdx)
|
||||
indexObject := this.Index(idx, 0, core.NewQModelIndex())
|
||||
// replace third param with []int{} to update all attributes instead
|
||||
this.DataChanged(indexObject, indexObject, []int{this.ackIdx})
|
||||
}
|
||||
|
|
|
@ -16,11 +16,30 @@ W.Overlay {
|
|||
|
||||
//horizontalPadding: 15 * gcd.themeScale
|
||||
|
||||
ListModel { // MESSAGE OBJECTS ARE STORED HERE ...
|
||||
id: messagesModel
|
||||
Connections {
|
||||
target: mm
|
||||
onRowsInserted: {
|
||||
if (messagesListView.atYEnd) thymer.running = true
|
||||
|
||||
//todo: this won't fire for non-active convos
|
||||
windowItem.alert(0)
|
||||
if (gcd.os == "android" && windowItem.activeFocusItem == null) {
|
||||
androidCwtchActivity.notification = "New Content"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// onRowsInserted is firing after the model is updated but before the delegate is inflated
|
||||
// causing positionViewAtEnd() to scroll to "just above the last message"
|
||||
// so we use this timer to delay scrolling by a few milliseconds
|
||||
Timer {
|
||||
id: thymer
|
||||
interval: 30
|
||||
onTriggered: {
|
||||
thymer.running = false
|
||||
messagesListView.positionViewAtEnd()
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: ListView {
|
||||
id: messagesListView
|
||||
|
@ -28,22 +47,26 @@ W.Overlay {
|
|||
Layout.fillWidth: true
|
||||
|
||||
width: parent.width
|
||||
model: mm//messagesModel//
|
||||
model: mm
|
||||
spacing: 6
|
||||
|
||||
clip: true
|
||||
ScrollBar.vertical: Opaque.ScrollBar {}
|
||||
maximumFlickVelocity: 1250
|
||||
|
||||
section.delegate: sectionHeading
|
||||
section.property: "Day"
|
||||
|
||||
|
||||
delegate: W.Message {
|
||||
handle: PeerID
|
||||
from: PeerID
|
||||
displayName: mm.getNick(PeerID)
|
||||
message: JSON.parse(RawMessage).d
|
||||
message: JSON.parse(RawMessage).d+"//"+Signature
|
||||
rawMessage: RawMessage
|
||||
image: mm.getImage(PeerID)
|
||||
messageID: "-1"//_mid
|
||||
fromMe: PeerID == gcd.SelectedProfile
|
||||
messageID: Signature
|
||||
fromMe: PeerID == gcd.selectedProfile
|
||||
timestamp: parseInt(Timestamp)
|
||||
ackd: Acknowledged
|
||||
error: Error
|
||||
|
@ -53,119 +76,48 @@ W.Overlay {
|
|||
width: messagesListView.width
|
||||
}
|
||||
|
||||
Component {
|
||||
id: sectionHeading
|
||||
Rectangle {// ⟵ outer rect because anchors._Margin isnt supported here
|
||||
// with qt 5.15+ this↓ can be changed to...
|
||||
// required property string section
|
||||
property string txt: section
|
||||
color: Theme.backgroundMainColor
|
||||
width: childrenRect.width
|
||||
height: childrenRect.height + 12
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Rectangle {
|
||||
opacity: 1
|
||||
width: childrenRect.width + 66
|
||||
height: childrenRect.height + 6
|
||||
color: Theme.messageFromOtherBackgroundColor
|
||||
radius: 15
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
|
||||
Text {
|
||||
// ... and this can be changed to
|
||||
// text: parent.parent.section
|
||||
text: parent.parent.txt
|
||||
font.pixelSize: Theme.chatSize * gcd.themeScale
|
||||
color: Theme.messageFromOtherTextColor
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: gcd
|
||||
|
||||
onClearMessages: function() {
|
||||
messagesModel.clear()
|
||||
messagesListView.model = null
|
||||
messagesListView.model = mm
|
||||
}
|
||||
|
||||
onAppendMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ackd, error) {
|
||||
return
|
||||
var msg
|
||||
try {
|
||||
msg = JSON.parse(message)
|
||||
} catch (e) {
|
||||
msg = {"o": 1, "d": "(legacy message type) " + message}
|
||||
}
|
||||
if (msg.o != 1) return
|
||||
|
||||
var date = new Date(ts * 1000);
|
||||
if (messagesModel.count != 0) {
|
||||
var prevDate = new Date(messagesModel.get(messagesModel.count-1)["_ts"] * 1000);
|
||||
if (prevDate.getFullYear() != date.getFullYear()
|
||||
|| prevDate.getMonth() != date.getMonth()
|
||||
|| prevDate.getUTCDate() != date.getUTCDate()) {
|
||||
// new Day detected, Add Date message divider
|
||||
messagesModel.append({
|
||||
"_handle": "calendar",
|
||||
"_from": "calendar",
|
||||
"_displayName": "calendar",
|
||||
"_message": Qt.formatDateTime(date, "MMMM dd, yyyy"),
|
||||
"_rawMessage": "",
|
||||
"_image": "",
|
||||
"_mid": "",
|
||||
"_fromMe": false,
|
||||
"_ts": ts,
|
||||
"_ackd": true,
|
||||
"_error": "",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
messagesModel.append({
|
||||
"_handle": handle,
|
||||
"_from": from,
|
||||
"_displayName": displayName,
|
||||
"_message": msg.d,
|
||||
"_rawMessage":msg.d,
|
||||
"_image": image,
|
||||
"_mid": mid,
|
||||
"_fromMe": fromMe,
|
||||
"_ts": ts,
|
||||
"_ackd": ackd,
|
||||
"_error": error == true ? "this message failed to send" : "",
|
||||
})
|
||||
|
||||
messagesListView.positionViewAtEnd()
|
||||
|
||||
// If the window is out of focus, alert the user (makes taskbar light up)
|
||||
windowItem.alert(0)
|
||||
if (gcd.os == "android" && windowItem.activeFocusItem == null) {
|
||||
androidCwtchActivity.notification = "New Content"
|
||||
}
|
||||
}
|
||||
|
||||
onPrependMessage: function(handle, from, displayName, message, image, mid, fromMe, ts, ackd, error) {
|
||||
return
|
||||
var msg
|
||||
try {
|
||||
msg = JSON.parse(message)
|
||||
} catch (e) {
|
||||
msg = {"o": 1, "d": "(legacy message type) " + message}
|
||||
}
|
||||
if (msg.o != 1) return
|
||||
|
||||
var date = new Date(ts * 1000);
|
||||
if (messagesModel.count != 0) {
|
||||
var prevDate = new Date(messagesModel.get(0)["_ts"] * 1000);
|
||||
|
||||
if (prevDate.getFullYear() != date.getFullYear()
|
||||
|| prevDate.getMonth() != date.getMonth()
|
||||
|| prevDate.getUTCDate() != date.getUTCDate()) {
|
||||
messagesModel.insert(0, {
|
||||
"_handle": "calendar",
|
||||
"_from": "calendar",
|
||||
"_displayName": "calendar",
|
||||
"_message": Qt.formatDateTime(prevDate, "MMMM dd, yyyy"),
|
||||
"_rawMessage": "",
|
||||
"_image": "",
|
||||
"_mid": "",
|
||||
"_fromMe": false,
|
||||
"_ts": ts,
|
||||
"_ackd": true,
|
||||
"_error": "",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
messagesModel.insert(0, {
|
||||
"_handle": handle,
|
||||
"_from": from,
|
||||
"_displayName": displayName,
|
||||
"_message": msg.d,
|
||||
"_rawMessage":msg.d,
|
||||
"_image": image,
|
||||
"_mid": mid,
|
||||
"_fromMe": fromMe,
|
||||
"_ts": ts,
|
||||
"_ackd": ackd,
|
||||
"_error": error == true ? "this message failed to send" : "",
|
||||
})
|
||||
|
||||
messagesListView.positionViewAtEnd()
|
||||
messagesListView.positionViewAtEnd()
|
||||
thymer.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Reference in New Issue