Start refactoring various things in message rendering and sending
This commit is contained in:
@ -17,7 +17,7 @@
|
||||
package messages
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
@ -29,38 +29,51 @@ import (
|
||||
"maunium.net/go/gomuks/ui/widget"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(&BaseMessage{})
|
||||
}
|
||||
|
||||
type BaseMessage struct {
|
||||
MsgID string
|
||||
MsgTxnID string
|
||||
MsgType mautrix.MessageType
|
||||
MsgSenderID string
|
||||
MsgSender string
|
||||
MsgSenderColor tcell.Color
|
||||
MsgTimestamp time.Time
|
||||
MsgState ifc.MessageState
|
||||
MsgState mautrix.OutgoingEventState
|
||||
MsgIsHighlight bool
|
||||
MsgIsService bool
|
||||
MsgSource json.RawMessage
|
||||
buffer []tstring.TString
|
||||
plainBuffer []tstring.TString
|
||||
}
|
||||
|
||||
func newBaseMessage(id, sender, displayname string, msgtype mautrix.MessageType, timestamp time.Time) BaseMessage {
|
||||
func newBaseMessage(event *mautrix.Event, displayname string) BaseMessage {
|
||||
msgtype := event.Content.MsgType
|
||||
if len(msgtype) == 0 {
|
||||
msgtype = mautrix.MessageType(event.Type.String())
|
||||
}
|
||||
|
||||
return BaseMessage{
|
||||
MsgSenderID: sender,
|
||||
MsgSenderID: event.Sender,
|
||||
MsgSender: displayname,
|
||||
MsgTimestamp: timestamp,
|
||||
MsgSenderColor: widget.GetHashColor(sender),
|
||||
MsgTimestamp: unixToTime(event.Timestamp),
|
||||
MsgSenderColor: widget.GetHashColor(event.Sender),
|
||||
MsgType: msgtype,
|
||||
MsgID: id,
|
||||
MsgState: ifc.MessageStateDefault,
|
||||
MsgID: event.ID,
|
||||
MsgTxnID: event.Unsigned.TransactionID,
|
||||
MsgState: event.Unsigned.OutgoingState,
|
||||
MsgIsHighlight: false,
|
||||
MsgIsService: false,
|
||||
MsgSource: event.Content.VeryRaw,
|
||||
}
|
||||
}
|
||||
|
||||
func unixToTime(unix int64) time.Time {
|
||||
timestamp := time.Now()
|
||||
if unix != 0 {
|
||||
timestamp = time.Unix(unix/1000, unix%1000*1000)
|
||||
}
|
||||
return timestamp
|
||||
}
|
||||
|
||||
func (msg *BaseMessage) RegisterMatrix(matrix ifc.MatrixContainer) {}
|
||||
|
||||
// Sender gets the string that should be displayed as the sender of this message.
|
||||
@ -71,9 +84,9 @@ func (msg *BaseMessage) RegisterMatrix(matrix ifc.MatrixContainer) {}
|
||||
// In any other case, the sender is the display name of the user who sent the message.
|
||||
func (msg *BaseMessage) Sender() string {
|
||||
switch msg.MsgState {
|
||||
case ifc.MessageStateSending:
|
||||
case mautrix.EventStateLocalEcho:
|
||||
return "Sending..."
|
||||
case ifc.MessageStateFailed:
|
||||
case mautrix.EventStateSendFail:
|
||||
return "Error"
|
||||
}
|
||||
switch msg.MsgType {
|
||||
@ -93,13 +106,17 @@ func (msg *BaseMessage) RealSender() string {
|
||||
return msg.MsgSender
|
||||
}
|
||||
|
||||
func (msg *BaseMessage) NotificationSenderName() string {
|
||||
return msg.MsgSender
|
||||
}
|
||||
|
||||
func (msg *BaseMessage) getStateSpecificColor() tcell.Color {
|
||||
switch msg.MsgState {
|
||||
case ifc.MessageStateSending:
|
||||
case mautrix.EventStateLocalEcho:
|
||||
return tcell.ColorGray
|
||||
case ifc.MessageStateFailed:
|
||||
case mautrix.EventStateSendFail:
|
||||
return tcell.ColorRed
|
||||
case ifc.MessageStateDefault:
|
||||
case mautrix.EventStateDefault:
|
||||
fallthrough
|
||||
default:
|
||||
return tcell.ColorDefault
|
||||
@ -154,17 +171,6 @@ func (msg *BaseMessage) TimestampColor() tcell.Color {
|
||||
return msg.getStateSpecificColor()
|
||||
}
|
||||
|
||||
// Buffer returns the computed text buffer.
|
||||
//
|
||||
// The buffer contains the text of the message split into lines with a maximum
|
||||
// width of whatever was provided to CalculateBuffer().
|
||||
//
|
||||
// N.B. This will NOT automatically calculate the buffer if it hasn't been
|
||||
// calculated already, as that requires the target width.
|
||||
func (msg *BaseMessage) Buffer() []tstring.TString {
|
||||
return msg.buffer
|
||||
}
|
||||
|
||||
// Height returns the number of rows in the computed buffer (see Buffer()).
|
||||
func (msg *BaseMessage) Height() int {
|
||||
return len(msg.buffer)
|
||||
@ -197,15 +203,11 @@ func (msg *BaseMessage) Type() mautrix.MessageType {
|
||||
return msg.MsgType
|
||||
}
|
||||
|
||||
func (msg *BaseMessage) SetType(msgtype mautrix.MessageType) {
|
||||
msg.MsgType = msgtype
|
||||
}
|
||||
|
||||
func (msg *BaseMessage) State() ifc.MessageState {
|
||||
func (msg *BaseMessage) State() mautrix.OutgoingEventState {
|
||||
return msg.MsgState
|
||||
}
|
||||
|
||||
func (msg *BaseMessage) SetState(state ifc.MessageState) {
|
||||
func (msg *BaseMessage) SetState(state mautrix.OutgoingEventState) {
|
||||
msg.MsgState = state
|
||||
}
|
||||
|
||||
@ -225,6 +227,10 @@ func (msg *BaseMessage) SetIsService(isService bool) {
|
||||
msg.MsgIsService = isService
|
||||
}
|
||||
|
||||
func (msg *BaseMessage) Source() json.RawMessage {
|
||||
return msg.MsgSource
|
||||
}
|
||||
|
||||
func (msg *BaseMessage) Draw(screen mauview.Screen) {
|
||||
for y, line := range msg.buffer {
|
||||
line.Draw(screen, 0, y)
|
||||
|
@ -17,28 +17,21 @@
|
||||
package messages
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
|
||||
"maunium.net/go/gomuks/config"
|
||||
"maunium.net/go/gomuks/ui/messages/tstring"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(&ExpandedTextMessage{})
|
||||
}
|
||||
|
||||
type ExpandedTextMessage struct {
|
||||
BaseMessage
|
||||
MsgText tstring.TString
|
||||
}
|
||||
|
||||
// NewExpandedTextMessage creates a new ExpandedTextMessage object with the provided values and the default state.
|
||||
func NewExpandedTextMessage(id, sender, displayname string, msgtype mautrix.MessageType, text tstring.TString, timestamp time.Time) UIMessage {
|
||||
func NewExpandedTextMessage(event *mautrix.Event, displayname string, text tstring.TString) UIMessage {
|
||||
return &ExpandedTextMessage{
|
||||
BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
|
||||
BaseMessage: newBaseMessage(event, displayname),
|
||||
MsgText: text,
|
||||
}
|
||||
}
|
||||
|
@ -17,13 +17,12 @@
|
||||
package messages
|
||||
|
||||
import (
|
||||
"maunium.net/go/gomuks/ui/messages/html"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mauview"
|
||||
"maunium.net/go/tcell"
|
||||
|
||||
"maunium.net/go/gomuks/config"
|
||||
"maunium.net/go/gomuks/ui/messages/html"
|
||||
)
|
||||
|
||||
type HTMLMessage struct {
|
||||
@ -36,7 +35,7 @@ type HTMLMessage struct {
|
||||
|
||||
func NewHTMLMessage(event *mautrix.Event, displayname string, root html.Entity) UIMessage {
|
||||
return &HTMLMessage{
|
||||
BaseMessage: newBaseMessage(event.ID, event.Sender, displayname, event.Content.MsgType, unixToTime(event.Timestamp)),
|
||||
BaseMessage: newBaseMessage(event, displayname),
|
||||
Root: root,
|
||||
}
|
||||
}
|
||||
|
@ -18,10 +18,8 @@ package messages
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/tcell"
|
||||
@ -33,10 +31,6 @@ import (
|
||||
"maunium.net/go/gomuks/ui/messages/tstring"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(&ImageMessage{})
|
||||
}
|
||||
|
||||
type ImageMessage struct {
|
||||
BaseMessage
|
||||
Body string
|
||||
@ -48,9 +42,9 @@ type ImageMessage struct {
|
||||
}
|
||||
|
||||
// NewImageMessage creates a new ImageMessage object with the provided values and the default state.
|
||||
func NewImageMessage(matrix ifc.MatrixContainer, id, sender, displayname string, msgtype mautrix.MessageType, body, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
|
||||
func NewImageMessage(matrix ifc.MatrixContainer, event *mautrix.Event, displayname string, body, homeserver, fileID string, data []byte) UIMessage {
|
||||
return &ImageMessage{
|
||||
newBaseMessage(id, sender, displayname, msgtype, timestamp),
|
||||
newBaseMessage(event, displayname),
|
||||
body,
|
||||
homeserver,
|
||||
fileID,
|
||||
|
@ -20,12 +20,20 @@ import (
|
||||
"maunium.net/go/gomuks/config"
|
||||
"maunium.net/go/gomuks/interface"
|
||||
"maunium.net/go/mauview"
|
||||
"maunium.net/go/tcell"
|
||||
)
|
||||
|
||||
// UIMessage is a wrapper for the content and metadata of a Matrix message intended to be displayed.
|
||||
type UIMessage interface {
|
||||
ifc.Message
|
||||
|
||||
Sender() string
|
||||
SenderColor() tcell.Color
|
||||
TextColor() tcell.Color
|
||||
TimestampColor() tcell.Color
|
||||
FormatTime() string
|
||||
FormatDate() string
|
||||
|
||||
CalculateBuffer(preferences config.UserPreferences, width int)
|
||||
Draw(screen mauview.Screen)
|
||||
Height() int
|
||||
|
@ -1,71 +0,0 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2019 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package messages
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"maunium.net/go/tcell"
|
||||
)
|
||||
|
||||
// BasicMeta is a simple variable store implementation of MessageMeta.
|
||||
type BasicMeta struct {
|
||||
BSender string
|
||||
BTimestamp time.Time
|
||||
BSenderColor, BTextColor, BTimestampColor tcell.Color
|
||||
}
|
||||
|
||||
// Sender gets the string that should be displayed as the sender of this message.
|
||||
func (meta *BasicMeta) Sender() string {
|
||||
return meta.BSender
|
||||
}
|
||||
|
||||
func (meta *BasicMeta) SenderID() string {
|
||||
return meta.BSender
|
||||
}
|
||||
|
||||
// SenderColor returns the color the name of the sender should be shown in.
|
||||
func (meta *BasicMeta) SenderColor() tcell.Color {
|
||||
return meta.BSenderColor
|
||||
}
|
||||
|
||||
// Timestamp returns the full time when the message was sent.
|
||||
func (meta *BasicMeta) Timestamp() time.Time {
|
||||
return meta.BTimestamp
|
||||
}
|
||||
|
||||
// FormatTime returns the formatted time when the message was sent.
|
||||
func (meta *BasicMeta) FormatTime() string {
|
||||
return meta.BTimestamp.Format(TimeFormat)
|
||||
}
|
||||
|
||||
// FormatDate returns the formatted date when the message was sent.
|
||||
func (meta *BasicMeta) FormatDate() string {
|
||||
return meta.BTimestamp.Format(DateFormat)
|
||||
}
|
||||
|
||||
// TextColor returns the color the actual content of the message should be shown in.
|
||||
func (meta *BasicMeta) TextColor() tcell.Color {
|
||||
return meta.BTextColor
|
||||
}
|
||||
|
||||
// TimestampColor returns the color the timestamp should be shown in.
|
||||
//
|
||||
// This usually does not apply to the date, as it is rendered separately from the message.
|
||||
func (meta *BasicMeta) TimestampColor() tcell.Color {
|
||||
return meta.BTimestampColor
|
||||
}
|
@ -18,9 +18,7 @@ package messages
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/tcell"
|
||||
@ -28,12 +26,33 @@ import (
|
||||
"maunium.net/go/gomuks/debug"
|
||||
"maunium.net/go/gomuks/interface"
|
||||
"maunium.net/go/gomuks/matrix/rooms"
|
||||
"maunium.net/go/gomuks/ui/messages/html"
|
||||
"maunium.net/go/gomuks/ui/messages/tstring"
|
||||
"maunium.net/go/gomuks/ui/widget"
|
||||
htmlp "maunium.net/go/gomuks/ui/messages/html"
|
||||
)
|
||||
|
||||
func ParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) UIMessage {
|
||||
msg := directParseEvent(matrix, room, evt)
|
||||
if msg == nil {
|
||||
return nil
|
||||
}
|
||||
if len(evt.Content.GetReplyTo()) > 0 {
|
||||
roomID := evt.Content.RelatesTo.InReplyTo.RoomID
|
||||
if len(roomID) == 0 {
|
||||
roomID = room.ID
|
||||
}
|
||||
replyToEvt, _ := matrix.GetEvent(room, evt.Content.GetReplyTo())
|
||||
if replyToEvt != nil {
|
||||
// TODO add reply header
|
||||
} else {
|
||||
// TODO add unknown reply header
|
||||
}
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
func directParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) UIMessage {
|
||||
switch evt.Type {
|
||||
case mautrix.EventSticker:
|
||||
evt.Content.MsgType = mautrix.MsgImage
|
||||
@ -48,14 +67,6 @@ func ParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event
|
||||
return nil
|
||||
}
|
||||
|
||||
func unixToTime(unix int64) time.Time {
|
||||
timestamp := time.Now()
|
||||
if unix != 0 {
|
||||
timestamp = time.Unix(unix/1000, unix%1000*1000)
|
||||
}
|
||||
return timestamp
|
||||
}
|
||||
|
||||
func ParseStateEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) UIMessage {
|
||||
displayname := evt.Sender
|
||||
member := room.GetMember(evt.Sender)
|
||||
@ -91,8 +102,7 @@ func ParseStateEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.
|
||||
case mautrix.StateAliases:
|
||||
text = ParseAliasEvent(evt, displayname)
|
||||
}
|
||||
ts := unixToTime(evt.Timestamp)
|
||||
return NewExpandedTextMessage(evt.ID, evt.Sender, displayname, mautrix.MessageType(evt.Type.Type), text, ts)
|
||||
return NewExpandedTextMessage(evt, displayname, text)
|
||||
}
|
||||
|
||||
func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) UIMessage {
|
||||
@ -103,39 +113,20 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Eve
|
||||
}
|
||||
if len(evt.Content.GetReplyTo()) > 0 {
|
||||
evt.Content.RemoveReplyFallback()
|
||||
roomID := evt.Content.RelatesTo.InReplyTo.RoomID
|
||||
if len(roomID) == 0 {
|
||||
roomID = room.ID
|
||||
}
|
||||
replyToEvt, _ := matrix.GetEvent(room, evt.Content.GetReplyTo())
|
||||
if replyToEvt != nil {
|
||||
replyToEvt.Content.RemoveReplyFallback()
|
||||
if len(replyToEvt.Content.FormattedBody) == 0 {
|
||||
replyToEvt.Content.FormattedBody = html.EscapeString(replyToEvt.Content.Body)
|
||||
}
|
||||
evt.Content.FormattedBody = fmt.Sprintf(
|
||||
"In reply to <a href='https://matrix.to/#/%[1]s'>%[1]s</a><blockquote>%[2]s</blockquote><br/><br/>%[3]s",
|
||||
replyToEvt.Sender, replyToEvt.Content.FormattedBody, evt.Content.FormattedBody)
|
||||
} else {
|
||||
evt.Content.FormattedBody = fmt.Sprintf(
|
||||
"In reply to unknown event https://matrix.to/#/%[1]s/%[2]s<br/>%[3]s",
|
||||
roomID, evt.Content.GetReplyTo(), evt.Content.FormattedBody)
|
||||
}
|
||||
}
|
||||
ts := unixToTime(evt.Timestamp)
|
||||
switch evt.Content.MsgType {
|
||||
case "m.text", "m.notice", "m.emote":
|
||||
if evt.Content.Format == mautrix.FormatHTML {
|
||||
return NewHTMLMessage(evt, displayname, htmlp.Parse(room, evt, displayname))
|
||||
return NewHTMLMessage(evt, displayname, html.Parse(room, evt, displayname))
|
||||
}
|
||||
evt.Content.Body = strings.Replace(evt.Content.Body, "\t", " ", -1)
|
||||
return NewTextMessage(evt.ID, evt.Sender, displayname, evt.Content.MsgType, evt.Content.Body, ts)
|
||||
return NewTextMessage(evt, displayname, evt.Content.Body)
|
||||
case "m.image":
|
||||
data, hs, id, err := matrix.Download(evt.Content.URL)
|
||||
if err != nil {
|
||||
debug.Printf("Failed to download %s: %v", evt.Content.URL, err)
|
||||
}
|
||||
return NewImageMessage(matrix, evt.ID, evt.Sender, displayname, evt.Content.MsgType, evt.Content.Body, hs, id, data, ts)
|
||||
return NewImageMessage(matrix, evt, displayname, evt.Content.Body, hs, id, data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -220,8 +211,7 @@ func ParseMembershipEvent(room *rooms.Room, evt *mautrix.Event) UIMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
ts := unixToTime(evt.Timestamp)
|
||||
return NewExpandedTextMessage(evt.ID, evt.Sender, displayname, "m.room.member", text, ts)
|
||||
return NewExpandedTextMessage(evt, displayname, text)
|
||||
}
|
||||
|
||||
func ParseAliasEvent(evt *mautrix.Event, displayname string) tstring.TString {
|
||||
|
@ -17,21 +17,14 @@
|
||||
package messages
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
|
||||
"maunium.net/go/gomuks/config"
|
||||
"maunium.net/go/gomuks/interface"
|
||||
"maunium.net/go/gomuks/ui/messages/tstring"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(&TextMessage{})
|
||||
}
|
||||
|
||||
type TextMessage struct {
|
||||
BaseMessage
|
||||
cache tstring.TString
|
||||
@ -39,9 +32,9 @@ type TextMessage struct {
|
||||
}
|
||||
|
||||
// NewTextMessage creates a new UITextMessage object with the provided values and the default state.
|
||||
func NewTextMessage(id, sender, displayname string, msgtype mautrix.MessageType, text string, timestamp time.Time) UIMessage {
|
||||
func NewTextMessage(event *mautrix.Event, displayname string, text string) UIMessage {
|
||||
return &TextMessage{
|
||||
BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
|
||||
BaseMessage: newBaseMessage(event, displayname),
|
||||
MsgText: text,
|
||||
}
|
||||
}
|
||||
@ -59,16 +52,6 @@ func (msg *TextMessage) getCache() tstring.TString {
|
||||
return msg.cache
|
||||
}
|
||||
|
||||
func (msg *TextMessage) SetType(msgtype mautrix.MessageType) {
|
||||
msg.BaseMessage.SetType(msgtype)
|
||||
msg.cache = nil
|
||||
}
|
||||
|
||||
func (msg *TextMessage) SetState(state ifc.MessageState) {
|
||||
msg.BaseMessage.SetState(state)
|
||||
msg.cache = nil
|
||||
}
|
||||
|
||||
func (msg *TextMessage) SetIsHighlight(isHighlight bool) {
|
||||
msg.BaseMessage.SetIsHighlight(isHighlight)
|
||||
msg.cache = nil
|
||||
|
Reference in New Issue
Block a user