2020-10-09 18:10:03 +00:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"cwtch.im/cwtch/model"
|
|
|
|
"cwtch.im/ui/go/the"
|
2020-10-20 22:57:34 +00:00
|
|
|
"encoding/hex"
|
2020-12-09 07:03:22 +00:00
|
|
|
"fmt"
|
2020-10-09 18:10:03 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/log"
|
|
|
|
"github.com/therecipe/qt/core"
|
|
|
|
"reflect"
|
|
|
|
)
|
|
|
|
|
|
|
|
type MessageModel struct {
|
|
|
|
core.QAbstractTableModel
|
|
|
|
|
2020-10-20 22:57:34 +00:00
|
|
|
ackIdx int
|
2020-10-09 18:10:03 +00:00
|
|
|
handle string
|
2020-11-23 21:13:09 +00:00
|
|
|
_ func(string) `signal:"setHandle,auto"`
|
2020-10-09 18:10:03 +00:00
|
|
|
|
|
|
|
_ map[int]*core.QByteArray `property:"roles"`
|
|
|
|
_ func() `constructor:"init"`
|
|
|
|
|
2020-12-09 00:37:08 +00:00
|
|
|
_ func(int) *MessageWrapper `slot:"getMessage,auto"`
|
2020-10-09 18:10:03 +00:00
|
|
|
_ func(int) `signal:"addMessage,auto"`
|
2020-10-20 22:57:34 +00:00
|
|
|
_ func(int) `signal:"editMessage,auto"`
|
|
|
|
_ func() `signal:"requestEIR,auto"`
|
2020-10-09 18:10:03 +00:00
|
|
|
|
|
|
|
_ func(string) string `slot:"getNick,auto"`
|
|
|
|
_ func(string) string `slot:"getImage,auto"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type MessageWrapper struct {
|
|
|
|
core.QObject
|
2020-12-09 00:37:08 +00:00
|
|
|
model.Message
|
|
|
|
|
|
|
|
_ int64 `property:"timestamp"`
|
|
|
|
_ string `property:"peerID"`
|
|
|
|
_ bool `property:"acknowledged"`
|
|
|
|
_ string `property:"rawMessage"`
|
|
|
|
_ string `property:"error"`
|
|
|
|
_ string `property:"day"`
|
|
|
|
_ string `property:"signature"`
|
|
|
|
_ bool `property:"ackd"`
|
|
|
|
}
|
2020-10-09 18:10:03 +00:00
|
|
|
|
2020-12-09 00:37:08 +00:00
|
|
|
type OverlayJSONObject struct {
|
|
|
|
Overlay int `json:"o"`
|
|
|
|
Data string `json:"d"`
|
2020-10-09 18:10:03 +00:00
|
|
|
}
|
|
|
|
|
2020-11-23 21:13:09 +00:00
|
|
|
func (this *MessageModel) Handle() string {
|
2020-10-09 18:10:03 +00:00
|
|
|
return this.handle
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) setHandle(handle string) {
|
|
|
|
this.handle = handle
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) init() {
|
2020-12-09 00:37:08 +00:00
|
|
|
sacrificialObject := NewMessageWrapper(nil)
|
|
|
|
mdt := reflect.TypeOf(*sacrificialObject)
|
2020-10-09 18:10:03 +00:00
|
|
|
roles := make(map[int]*core.QByteArray)
|
|
|
|
for i := 0; i < mdt.NumField(); i++ {
|
2020-12-09 00:37:08 +00:00
|
|
|
fieldName := mdt.Field(i).Name
|
|
|
|
if fieldName == "_" {
|
|
|
|
fieldName = mdt.Field(i).Tag.Get("property")
|
|
|
|
}
|
|
|
|
|
|
|
|
if fieldName == "acknowledged" {
|
2020-10-20 22:57:34 +00:00
|
|
|
this.ackIdx = int(core.Qt__UserRole) + 1 + i
|
|
|
|
}
|
2020-12-09 00:37:08 +00:00
|
|
|
roles[int(core.Qt__UserRole)+1+i] = core.NewQByteArray2(fieldName, -1)
|
2020-10-09 18:10:03 +00:00
|
|
|
}
|
|
|
|
roles[int(core.Qt__DisplayRole)] = core.NewQByteArray2("display", -1)
|
|
|
|
this.SetRoles(roles)
|
|
|
|
|
|
|
|
this.ConnectData(this.data)
|
|
|
|
this.ConnectRowCount(this.rowCount)
|
|
|
|
this.ConnectColumnCount(this.columnCount)
|
|
|
|
this.ConnectHeaderData(this.headerData)
|
|
|
|
this.ConnectRoleNames(this.roleNames)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) roleNames() map[int]*core.QByteArray {
|
|
|
|
return this.Roles()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) isGroup() bool {
|
|
|
|
return len(this.Handle()) == 32
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) getNick(handle string) string {
|
|
|
|
return GetNick(handle)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) getImage(handle string) string {
|
|
|
|
return GetProfilePic(handle)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) num() int {
|
|
|
|
if this.Handle() == "" || the.Peer == nil {
|
2020-10-20 22:57:34 +00:00
|
|
|
log.Debugf("MessageModel.num: early returning 0")
|
2020-10-09 18:10:03 +00:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
if this.isGroup() {
|
|
|
|
group := the.Peer.GetGroup(this.Handle())
|
|
|
|
if group != nil {
|
|
|
|
return len(group.Timeline.Messages) + len(group.UnacknowledgedMessages)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
contact := the.Peer.GetContact(this.Handle())
|
|
|
|
if contact != nil {
|
|
|
|
return len(contact.Timeline.Messages)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-20 22:57:34 +00:00
|
|
|
log.Warnf("MessageModel.num: group/contact was nil, returning 0")
|
2020-10-09 18:10:03 +00:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2020-12-09 07:03:22 +00:00
|
|
|
// caveat emptor: accessing messages this way returns a MessageWrapper QObject whose properties have not yet been
|
|
|
|
// initialized (but soon will be). accessing .Message parent class properties instead should work right away.
|
2020-10-09 18:10:03 +00:00
|
|
|
func (this *MessageModel) getMessage(idx int) *MessageWrapper {
|
2020-11-23 21:13:09 +00:00
|
|
|
modelmsg := model.Message{Message: "[an unexpected cwtch error occurred]"}
|
2020-10-20 22:57:34 +00:00
|
|
|
var ackd bool
|
2020-10-09 18:10:03 +00:00
|
|
|
|
|
|
|
if this.isGroup() {
|
|
|
|
group := the.Peer.GetGroup(this.Handle())
|
|
|
|
if idx >= len(group.Timeline.Messages) {
|
2020-11-23 21:13:09 +00:00
|
|
|
modelmsg = group.UnacknowledgedMessages[idx-len(group.Timeline.Messages)]
|
2020-10-09 18:10:03 +00:00
|
|
|
} else {
|
|
|
|
modelmsg = group.Timeline.Messages[idx]
|
2020-10-20 22:57:34 +00:00
|
|
|
ackd = true
|
2020-10-09 18:10:03 +00:00
|
|
|
}
|
|
|
|
} else {
|
2020-10-23 01:01:48 +00:00
|
|
|
if this.Handle() != "" && the.Peer != nil {
|
|
|
|
contact := the.Peer.GetContact(this.Handle())
|
|
|
|
if contact != nil {
|
|
|
|
if idx >= len(contact.Timeline.Messages) {
|
|
|
|
log.Errorf("requested message[%d] of only %d", idx, len(contact.Timeline.Messages))
|
|
|
|
} else {
|
|
|
|
modelmsg = contact.Timeline.Messages[idx]
|
|
|
|
ackd = modelmsg.Acknowledged
|
|
|
|
}
|
|
|
|
}
|
2020-10-09 18:10:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-09 00:37:08 +00:00
|
|
|
mw := NewMessageWrapper(nil)
|
|
|
|
mw.Message = modelmsg
|
|
|
|
mw.SetTimestamp(modelmsg.Timestamp.Unix())
|
|
|
|
mw.SetPeerID(modelmsg.PeerID)
|
|
|
|
mw.SetError(modelmsg.Error)
|
|
|
|
mw.SetAcknowledged(ackd)
|
|
|
|
mw.SetAckd(ackd)//??why both??
|
|
|
|
mw.SetDay(modelmsg.Timestamp.Format("January 2, 2006"))
|
|
|
|
mw.SetSignature(hex.EncodeToString(modelmsg.Signature))
|
|
|
|
mw.SetRawMessage(modelmsg.Message)
|
|
|
|
return mw
|
2020-10-09 18:10:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) data(index *core.QModelIndex, role int) *core.QVariant {
|
|
|
|
if !index.IsValid() {
|
|
|
|
return core.NewQVariant()
|
|
|
|
}
|
|
|
|
if index.Row() >= this.num() {
|
|
|
|
return core.NewQVariant()
|
|
|
|
}
|
|
|
|
|
|
|
|
if role == int(core.Qt__DisplayRole) {
|
|
|
|
role = index.Column() + int(core.Qt__UserRole) + 1
|
|
|
|
}
|
|
|
|
|
2020-12-09 07:03:22 +00:00
|
|
|
if role == this.ackIdx {
|
|
|
|
return core.NewQVariant1((*this.getMessage(index.Row())).Acknowledged)
|
2020-10-09 18:10:03 +00:00
|
|
|
}
|
|
|
|
|
2020-12-09 07:03:22 +00:00
|
|
|
return core.NewQVariant1(fmt.Sprintf("unimplemented role %s (%d)", this.roleNames()[role].ConstData(), role))
|
2020-10-09 18:10:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) headerData(section int, orientation core.Qt__Orientation, role int) *core.QVariant {
|
|
|
|
if role != int(core.Qt__DisplayRole) || orientation == core.Qt__Vertical {
|
|
|
|
return this.HeaderDataDefault(section, orientation, role)
|
|
|
|
}
|
|
|
|
|
2020-10-20 22:57:34 +00:00
|
|
|
mdt := reflect.TypeOf([]MessageWrapper{}).Elem()
|
2020-10-09 18:10:03 +00:00
|
|
|
return core.NewQVariant12(mdt.Field(section).Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) rowCount(parent *core.QModelIndex) int {
|
|
|
|
return this.num()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *MessageModel) columnCount(parent *core.QModelIndex) int {
|
|
|
|
return reflect.TypeOf(MessageWrapper{}).NumField()
|
|
|
|
}
|
|
|
|
|
2020-10-20 22:57:34 +00:00
|
|
|
// 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
|
2020-10-09 18:10:03 +00:00
|
|
|
func (this *MessageModel) addMessage(idx int) {
|
2020-10-20 22:57:34 +00:00
|
|
|
this.BeginInsertRows(core.NewQModelIndex(), idx, idx)
|
2020-10-09 18:10:03 +00:00
|
|
|
}
|
|
|
|
|
2020-10-20 22:57:34 +00:00
|
|
|
// perform this.EndInsertRows() on the gui thread after an AddMessage()
|
2020-10-09 18:10:03 +00:00
|
|
|
func (this *MessageModel) requestEIR() {
|
|
|
|
this.EndInsertRows()
|
|
|
|
}
|
|
|
|
|
2020-10-20 22:57:34 +00:00
|
|
|
// 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() {
|
2020-12-09 00:58:07 +00:00
|
|
|
log.Debugf("cant edit message %v. probably fine", idx)
|
2020-10-20 22:57:34 +00:00
|
|
|
return
|
|
|
|
}
|
2020-10-09 18:10:03 +00:00
|
|
|
|
2020-10-20 22:57:34 +00:00
|
|
|
indexObject := this.Index(idx, 0, core.NewQModelIndex())
|
|
|
|
// replace third param with []int{} to update all attributes instead
|
|
|
|
this.DataChanged(indexObject, indexObject, []int{this.ackIdx})
|
2020-10-09 18:10:03 +00:00
|
|
|
}
|