Unbreak things

This commit is contained in:
Tulir Asokan
2019-06-15 01:11:51 +03:00
parent a4ac699c93
commit a55ea42d7f
26 changed files with 985 additions and 568 deletions

View File

@ -27,44 +27,60 @@ import (
"maunium.net/go/tcell"
"maunium.net/go/gomuks/interface"
"maunium.net/go/gomuks/ui/messages/tstring"
"maunium.net/go/gomuks/ui/widget"
)
type BaseMessage struct {
MsgID string
MsgTxnID string
MsgType mautrix.MessageType
MsgSenderID string
MsgSender string
MsgSenderColor tcell.Color
MsgTimestamp time.Time
MsgState mautrix.OutgoingEventState
MsgIsHighlight bool
MsgIsService bool
MsgSource json.RawMessage
ReplyTo UIMessage
buffer []tstring.TString
type MessageRenderer interface {
Draw(screen mauview.Screen)
NotificationContent() string
PlainText() string
CalculateBuffer(prefs config.UserPreferences, width int, msg *UIMessage)
RegisterMatrix(matrix ifc.MatrixContainer)
Height() int
Clone() MessageRenderer
String() string
}
func newBaseMessage(event *mautrix.Event, displayname string) BaseMessage {
type UIMessage struct {
EventID string
TxnID string
Relation mautrix.RelatesTo
Type mautrix.MessageType
SenderID string
SenderName string
DefaultSenderColor tcell.Color
Timestamp time.Time
State mautrix.OutgoingEventState
IsHighlight bool
IsService bool
Source json.RawMessage
ReplyTo *UIMessage
Renderer MessageRenderer
}
const DateFormat = "January _2, 2006"
const TimeFormat = "15:04:05"
func newUIMessage(event *mautrix.Event, displayname string, renderer MessageRenderer) *UIMessage {
msgtype := event.Content.MsgType
if len(msgtype) == 0 {
msgtype = mautrix.MessageType(event.Type.String())
}
return BaseMessage{
MsgSenderID: event.Sender,
MsgSender: displayname,
MsgTimestamp: unixToTime(event.Timestamp),
MsgSenderColor: widget.GetHashColor(event.Sender),
MsgType: msgtype,
MsgID: event.ID,
MsgTxnID: event.Unsigned.TransactionID,
MsgState: event.Unsigned.OutgoingState,
MsgIsHighlight: false,
MsgIsService: false,
MsgSource: event.Content.VeryRaw,
return &UIMessage{
SenderID: event.Sender,
SenderName: displayname,
Timestamp: unixToTime(event.Timestamp),
DefaultSenderColor: widget.GetHashColor(event.Sender),
Type: msgtype,
EventID: event.ID,
TxnID: event.Unsigned.TransactionID,
Relation: *event.Content.GetRelatesTo(),
State: event.Unsigned.OutgoingState,
IsHighlight: false,
IsService: false,
Source: event.Content.VeryRaw,
Renderer: renderer,
}
}
@ -76,44 +92,38 @@ func unixToTime(unix int64) time.Time {
return timestamp
}
func (msg *BaseMessage) RegisterMatrix(matrix ifc.MatrixContainer) {}
// Sender gets the string that should be displayed as the sender of this message.
//
// If the message is being sent, the sender is "Sending...".
// If sending has failed, the sender is "Error".
// If the message is an emote, the sender is blank.
// 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 {
func (msg *UIMessage) Sender() string {
switch msg.State {
case mautrix.EventStateLocalEcho:
return "Sending..."
case mautrix.EventStateSendFail:
return "Error"
}
switch msg.MsgType {
switch msg.Type {
case "m.emote":
// Emotes don't show a separate sender, it's included in the buffer.
return ""
default:
return msg.MsgSender
return msg.SenderName
}
}
func (msg *BaseMessage) SenderID() string {
return msg.MsgSenderID
func (msg *UIMessage) NotificationSenderName() string {
return msg.SenderName
}
func (msg *BaseMessage) RealSender() string {
return msg.MsgSender
func (msg *UIMessage) NotificationContent() string {
return msg.Renderer.NotificationContent()
}
func (msg *BaseMessage) NotificationSenderName() string {
return msg.MsgSender
}
func (msg *BaseMessage) getStateSpecificColor() tcell.Color {
switch msg.MsgState {
func (msg *UIMessage) getStateSpecificColor() tcell.Color {
switch msg.State {
case mautrix.EventStateLocalEcho:
return tcell.ColorGray
case mautrix.EventStateSendFail:
@ -132,31 +142,31 @@ func (msg *BaseMessage) getStateSpecificColor() tcell.Color {
//
// In any other case, the color is whatever is specified in the Message struct.
// Usually that means it is the hash-based color of the sender (see ui/widget/color.go)
func (msg *BaseMessage) SenderColor() tcell.Color {
func (msg *UIMessage) SenderColor() tcell.Color {
stateColor := msg.getStateSpecificColor()
switch {
case stateColor != tcell.ColorDefault:
return stateColor
case msg.MsgType == "m.room.member":
return widget.GetHashColor(msg.MsgSender)
case msg.MsgIsService:
case msg.Type == "m.room.member":
return widget.GetHashColor(msg.SenderName)
case msg.IsService:
return tcell.ColorGray
default:
return msg.MsgSenderColor
return msg.DefaultSenderColor
}
}
// TextColor returns the color the actual content of the message should be shown in.
func (msg *BaseMessage) TextColor() tcell.Color {
func (msg *UIMessage) TextColor() tcell.Color {
stateColor := msg.getStateSpecificColor()
switch {
case stateColor != tcell.ColorDefault:
return stateColor
case msg.MsgIsService, msg.MsgType == "m.notice":
case msg.IsService, msg.Type == "m.notice":
return tcell.ColorGray
case msg.MsgIsHighlight:
case msg.IsHighlight:
return tcell.ColorYellow
case msg.MsgType == "m.room.member":
case msg.Type == "m.room.member":
return tcell.ColorGreen
default:
return tcell.ColorDefault
@ -169,14 +179,14 @@ func (msg *BaseMessage) TextColor() tcell.Color {
// gray and red respectively.
//
// However, other messages are the default color instead of a color stored in the struct.
func (msg *BaseMessage) TimestampColor() tcell.Color {
if msg.MsgIsService {
func (msg *UIMessage) TimestampColor() tcell.Color {
if msg.IsService {
return tcell.ColorGray
}
return msg.getStateSpecificColor()
}
func (msg *BaseMessage) ReplyHeight() int {
func (msg *UIMessage) ReplyHeight() int {
if msg.ReplyTo != nil {
return 1 + msg.ReplyTo.Height()
}
@ -184,102 +194,76 @@ func (msg *BaseMessage) ReplyHeight() int {
}
// Height returns the number of rows in the computed buffer (see Buffer()).
func (msg *BaseMessage) Height() int {
return msg.ReplyHeight() + len(msg.buffer)
func (msg *UIMessage) Height() int {
return msg.ReplyHeight() + msg.Renderer.Height()
}
// Timestamp returns the full timestamp when the message was sent.
func (msg *BaseMessage) Timestamp() time.Time {
return msg.MsgTimestamp
func (msg *UIMessage) Time() time.Time {
return msg.Timestamp
}
// FormatTime returns the formatted time when the message was sent.
func (msg *BaseMessage) FormatTime() string {
return msg.MsgTimestamp.Format(TimeFormat)
func (msg *UIMessage) FormatTime() string {
return msg.Timestamp.Format(TimeFormat)
}
// FormatDate returns the formatted date when the message was sent.
func (msg *BaseMessage) FormatDate() string {
return msg.MsgTimestamp.Format(DateFormat)
func (msg *UIMessage) FormatDate() string {
return msg.Timestamp.Format(DateFormat)
}
func (msg *BaseMessage) SameDate(message UIMessage) bool {
year1, month1, day1 := msg.Timestamp().Date()
year2, month2, day2 := message.Timestamp().Date()
func (msg *UIMessage) SameDate(message *UIMessage) bool {
year1, month1, day1 := msg.Timestamp.Date()
year2, month2, day2 := message.Timestamp.Date()
return day1 == day2 && month1 == month2 && year1 == year2
}
func (msg *BaseMessage) ID() string {
if len(msg.MsgID) == 0 {
return msg.MsgTxnID
func (msg *UIMessage) ID() string {
if len(msg.EventID) == 0 {
return msg.TxnID
}
return msg.MsgID
return msg.EventID
}
func (msg *BaseMessage) SetID(id string) {
msg.MsgID = id
func (msg *UIMessage) SetID(id string) {
msg.EventID = id
}
func (msg *BaseMessage) TxnID() string {
return msg.MsgTxnID
func (msg *UIMessage) SetIsHighlight(isHighlight bool) {
// TODO Textmessage cache needs to be cleared
msg.IsHighlight = isHighlight
}
func (msg *BaseMessage) Type() mautrix.MessageType {
return msg.MsgType
}
func (msg *BaseMessage) State() mautrix.OutgoingEventState {
return msg.MsgState
}
func (msg *BaseMessage) SetState(state mautrix.OutgoingEventState) {
msg.MsgState = state
}
func (msg *BaseMessage) IsHighlight() bool {
return msg.MsgIsHighlight
}
func (msg *BaseMessage) SetIsHighlight(isHighlight bool) {
msg.MsgIsHighlight = isHighlight
}
func (msg *BaseMessage) Source() json.RawMessage {
return msg.MsgSource
}
func (msg *BaseMessage) SetReplyTo(event UIMessage) {
msg.ReplyTo = event
}
func (msg *BaseMessage) Draw(screen mauview.Screen) {
func (msg *UIMessage) Draw(screen mauview.Screen) {
screen = msg.DrawReply(screen)
for y, line := range msg.buffer {
line.Draw(screen, 0, y)
}
msg.Renderer.Draw(screen)
}
func (msg *BaseMessage) clone() BaseMessage {
func (msg *UIMessage) Clone() *UIMessage {
clone := *msg
clone.buffer = nil
return clone
clone.Renderer = clone.Renderer.Clone()
return &clone
}
func (msg *BaseMessage) CalculateReplyBuffer(preferences config.UserPreferences, width int) {
func (msg *UIMessage) CalculateReplyBuffer(preferences config.UserPreferences, width int) {
if msg.ReplyTo == nil {
return
}
msg.ReplyTo.CalculateBuffer(preferences, width-1)
}
func (msg *BaseMessage) DrawReply(screen mauview.Screen) mauview.Screen {
func (msg *UIMessage) CalculateBuffer(preferences config.UserPreferences, width int) {
msg.Renderer.CalculateBuffer(preferences, width-1, msg)
}
func (msg *UIMessage) DrawReply(screen mauview.Screen) mauview.Screen {
if msg.ReplyTo == nil {
return screen
}
width, height := screen.Size()
replyHeight := msg.ReplyTo.Height()
widget.WriteLineSimpleColor(screen, "In reply to", 1, 0, tcell.ColorGreen)
widget.WriteLineSimpleColor(screen, msg.ReplyTo.RealSender(), 13, 0, msg.ReplyTo.SenderColor())
widget.WriteLineSimpleColor(screen, msg.ReplyTo.SenderName, 13, 0, msg.ReplyTo.SenderColor())
for y := 0; y < 1+replyHeight; y++ {
screen.SetCell(0, y, tcell.StyleDefault, '▊')
}
@ -288,16 +272,21 @@ func (msg *BaseMessage) DrawReply(screen mauview.Screen) mauview.Screen {
return mauview.NewProxyScreen(screen, 0, replyHeight+1, width, height-replyHeight-1)
}
func (msg *BaseMessage) String() string {
return fmt.Sprintf(`&messages.BaseMessage{
func (msg *UIMessage) String() string {
return fmt.Sprintf(`&messages.UIMessage{
ID="%s", TxnID="%s",
Type="%s", Timestamp=%s,
Sender={ID="%s", Name="%s", Color=#%X},
IsService=%t, IsHighlight=%t,
Renderer=%s,
}`,
msg.MsgID, msg.MsgTxnID,
msg.MsgType, msg.MsgTimestamp.String(),
msg.MsgSenderID, msg.MsgSender, msg.MsgSenderColor.Hex(),
msg.MsgIsService, msg.MsgIsHighlight,
msg.EventID, msg.TxnID,
msg.Type, msg.Timestamp.String(),
msg.SenderID, msg.SenderName, msg.DefaultSenderColor.Hex(),
msg.IsService, msg.IsHighlight, msg.Renderer.String(),
)
}
func (msg *UIMessage) PlainText() string {
return msg.Renderer.PlainText()
}

View File

@ -17,9 +17,12 @@
package messages
import (
"fmt"
"time"
ifc "maunium.net/go/gomuks/interface"
"maunium.net/go/mautrix"
"maunium.net/go/mauview"
"maunium.net/go/tcell"
"maunium.net/go/gomuks/config"
@ -27,55 +30,63 @@ import (
)
type ExpandedTextMessage struct {
BaseMessage
MsgText tstring.TString
Text tstring.TString
buffer []tstring.TString
}
// NewExpandedTextMessage creates a new ExpandedTextMessage object with the provided values and the default state.
func NewExpandedTextMessage(event *mautrix.Event, displayname string, text tstring.TString) UIMessage {
return &ExpandedTextMessage{
BaseMessage: newBaseMessage(event, displayname),
MsgText: text,
}
func NewExpandedTextMessage(event *mautrix.Event, displayname string, text tstring.TString) *UIMessage {
return newUIMessage(event, displayname, &ExpandedTextMessage{
Text: text,
})
}
func NewDateChangeMessage(text string) UIMessage {
func NewDateChangeMessage(text string) *UIMessage {
midnight := time.Now()
midnight = time.Date(midnight.Year(), midnight.Month(), midnight.Day(),
0, 0, 0, 0,
midnight.Location())
return &ExpandedTextMessage{
BaseMessage: BaseMessage{
MsgSenderID: "*",
MsgSender: "*",
MsgTimestamp: midnight,
MsgIsService: true,
return &UIMessage{
SenderID: "*",
SenderName: "*",
Timestamp: midnight,
IsService: true,
Renderer: &ExpandedTextMessage{
Text: tstring.NewColorTString(text, tcell.ColorGreen),
},
MsgText: tstring.NewColorTString(text, tcell.ColorGreen),
}
}
func (msg *ExpandedTextMessage) Clone() UIMessage {
func (msg *ExpandedTextMessage) Clone() MessageRenderer {
return &ExpandedTextMessage{
BaseMessage: msg.BaseMessage.clone(),
MsgText: msg.MsgText.Clone(),
Text: msg.Text.Clone(),
}
}
func (msg *ExpandedTextMessage) GenerateText() tstring.TString {
return msg.MsgText
}
func (msg *ExpandedTextMessage) NotificationContent() string {
return msg.MsgText.String()
return msg.Text.String()
}
func (msg *ExpandedTextMessage) PlainText() string {
return msg.MsgText.String()
return msg.Text.String()
}
func (msg *ExpandedTextMessage) CalculateBuffer(prefs config.UserPreferences, width int) {
msg.CalculateReplyBuffer(prefs, width)
msg.calculateBufferWithText(prefs, msg.MsgText, width)
func (msg *ExpandedTextMessage) String() string {
return fmt.Sprintf(`&messages.ExpandedTextMessage{Text="%s"}`, msg.Text.String())
}
func (msg *ExpandedTextMessage) CalculateBuffer(prefs config.UserPreferences, width int, uiMsg *UIMessage) {
msg.buffer = calculateBufferWithText(prefs, msg.Text, width, uiMsg)
}
func (msg *ExpandedTextMessage) Height() int {
return len(msg.buffer)
}
func (msg *ExpandedTextMessage) Draw(screen mauview.Screen) {
for y, line := range msg.buffer {
line.Draw(screen, 0, y)
}
}
func (msg *ExpandedTextMessage) RegisterMatrix(matrix ifc.MatrixContainer) {}

View File

@ -17,9 +17,7 @@
package messages
import (
"fmt"
"strings"
ifc "maunium.net/go/gomuks/interface"
"maunium.net/go/mautrix"
"maunium.net/go/mauview"
"maunium.net/go/tcell"
@ -29,30 +27,27 @@ import (
)
type HTMLMessage struct {
BaseMessage
Root html.Entity
FocusedBg tcell.Color
focused bool
}
func NewHTMLMessage(event *mautrix.Event, displayname string, root html.Entity) UIMessage {
return &HTMLMessage{
BaseMessage: newBaseMessage(event, displayname),
Root: root,
}
func NewHTMLMessage(event *mautrix.Event, displayname string, root html.Entity) *UIMessage {
return newUIMessage(event, displayname, &HTMLMessage{
Root: root,
})
}
func (hw *HTMLMessage) Clone() UIMessage {
func (hw *HTMLMessage) RegisterMatrix(matrix ifc.MatrixContainer) {}
func (hw *HTMLMessage) Clone() MessageRenderer {
return &HTMLMessage{
BaseMessage: hw.BaseMessage.clone(),
Root: hw.Root.Clone(),
FocusedBg: hw.FocusedBg,
Root: hw.Root.Clone(),
FocusedBg: hw.FocusedBg,
}
}
func (hw *HTMLMessage) Draw(screen mauview.Screen) {
screen = hw.DrawReply(screen)
if hw.focused {
screen.SetStyle(tcell.StyleDefault.Background(hw.FocusedBg))
}
@ -80,18 +75,17 @@ func (hw *HTMLMessage) OnPasteEvent(event mauview.PasteEvent) bool {
return false
}
func (hw *HTMLMessage) CalculateBuffer(preferences config.UserPreferences, width int) {
func (hw *HTMLMessage) CalculateBuffer(preferences config.UserPreferences, width int, msg *UIMessage) {
if width < 2 {
return
}
hw.CalculateReplyBuffer(preferences, width)
// TODO account for bare messages in initial startX
startX := 0
hw.Root.CalculateBuffer(width, startX, preferences.BareMessageView)
}
func (hw *HTMLMessage) Height() int {
return hw.ReplyHeight() + hw.Root.Height()
return hw.Root.Height()
}
func (hw *HTMLMessage) PlainText() string {
@ -103,8 +97,5 @@ func (hw *HTMLMessage) NotificationContent() string {
}
func (hw *HTMLMessage) String() string {
return fmt.Sprintf("&messages.HTMLMessage{\n" +
" Base=%s,\n" +
" Root=||\n%s\n" +
"}", strings.Replace(hw.BaseMessage.String(), "\n", "\n ", -1), hw.Root.String())
return hw.Root.String()
}

View File

@ -22,6 +22,7 @@ import (
"image/color"
"maunium.net/go/mautrix"
"maunium.net/go/mauview"
"maunium.net/go/tcell"
"maunium.net/go/gomuks/config"
@ -32,32 +33,30 @@ import (
)
type ImageMessage struct {
BaseMessage
Body string
Homeserver string
FileID string
data []byte
buffer []tstring.TString
matrix ifc.MatrixContainer
}
// NewImageMessage creates a new ImageMessage object with the provided values and the default state.
func NewImageMessage(matrix ifc.MatrixContainer, event *mautrix.Event, displayname string, body, homeserver, fileID string, data []byte) UIMessage {
return &ImageMessage{
newBaseMessage(event, displayname),
body,
homeserver,
fileID,
data,
matrix,
}
func NewImageMessage(matrix ifc.MatrixContainer, event *mautrix.Event, displayname string, body, homeserver, fileID string, data []byte) *UIMessage {
return newUIMessage(event, displayname, &ImageMessage{
Body: body,
Homeserver: homeserver,
FileID: fileID,
data: data,
matrix: matrix,
})
}
func (msg *ImageMessage) Clone() UIMessage {
func (msg *ImageMessage) Clone() MessageRenderer {
data := make([]byte, len(msg.data))
copy(data, msg.data)
return &ImageMessage{
BaseMessage: msg.BaseMessage.clone(),
Body: msg.Body,
Homeserver: msg.Homeserver,
FileID: msg.FileID,
@ -70,7 +69,7 @@ func (msg *ImageMessage) RegisterMatrix(matrix ifc.MatrixContainer) {
msg.matrix = matrix
if len(msg.data) == 0 {
go msg.updateData()
//FIXME go msg.updateData()
}
}
@ -82,6 +81,10 @@ func (msg *ImageMessage) PlainText() string {
return fmt.Sprintf("%s: %s", msg.Body, msg.matrix.GetDownloadURL(msg.Homeserver, msg.FileID))
}
func (msg *ImageMessage) String() string {
return fmt.Sprintf(`&messages.ImageMessage{Body="%s", Homeserver="%s", FileID="%s"}`, msg.Body, msg.Homeserver, msg.FileID)
}
func (msg *ImageMessage) updateData() {
defer debug.Recover()
debug.Print("Loading image:", msg.Homeserver, msg.FileID)
@ -101,14 +104,13 @@ func (msg *ImageMessage) Path() string {
// CalculateBuffer generates the internal buffer for this message that consists
// of the text of this message split into lines at most as wide as the width
// parameter.
func (msg *ImageMessage) CalculateBuffer(prefs config.UserPreferences, width int) {
func (msg *ImageMessage) CalculateBuffer(prefs config.UserPreferences, width int, uiMsg *UIMessage) {
if width < 2 {
return
}
msg.CalculateReplyBuffer(prefs, width)
if prefs.BareMessageView || prefs.DisableImages {
msg.calculateBufferWithText(prefs, tstring.NewTString(msg.PlainText()), width)
msg.buffer = calculateBufferWithText(prefs, tstring.NewTString(msg.PlainText()), width, uiMsg)
return
}
@ -121,3 +123,13 @@ func (msg *ImageMessage) CalculateBuffer(prefs config.UserPreferences, width int
msg.buffer = image.Render()
}
func (msg *ImageMessage) Height() int {
return len(msg.buffer)
}
func (msg *ImageMessage) Draw(screen mauview.Screen) {
for y, line := range msg.buffer {
line.Draw(screen, 0, y)
}
}

View File

@ -1,53 +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 (
"maunium.net/go/gomuks/config"
"maunium.net/go/gomuks/interface"
"maunium.net/go/mautrix"
"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
Type() mautrix.MessageType
Sender() string
SenderColor() tcell.Color
TextColor() tcell.Color
TimestampColor() tcell.Color
FormatTime() string
FormatDate() string
SameDate(message UIMessage) bool
SetReplyTo(message UIMessage)
CalculateBuffer(preferences config.UserPreferences, width int)
Draw(screen mauview.Screen)
Height() int
PlainText() string
Clone() UIMessage
RealSender() string
RegisterMatrix(matrix ifc.MatrixContainer)
}
const DateFormat = "January _2, 2006"
const TimeFormat = "15:04:05"

View File

@ -31,10 +31,10 @@ import (
"maunium.net/go/gomuks/ui/widget"
)
func getCachedEvent(mainView ifc.MainView, roomID, eventID string) UIMessage {
func getCachedEvent(mainView ifc.MainView, roomID, eventID string) *UIMessage {
if roomView := mainView.GetRoom(roomID); roomView != nil {
if replyToIfcMsg := roomView.GetEvent(eventID); replyToIfcMsg != nil {
if replyToMsg, ok := replyToIfcMsg.(UIMessage); ok && replyToMsg != nil {
if replyToMsg, ok := replyToIfcMsg.(*UIMessage); ok && replyToMsg != nil {
return replyToMsg
}
}
@ -42,24 +42,19 @@ func getCachedEvent(mainView ifc.MainView, roomID, eventID string) UIMessage {
return nil
}
func ParseEvent(matrix ifc.MatrixContainer, mainView ifc.MainView, room *rooms.Room, evt *mautrix.Event) UIMessage {
func ParseEvent(matrix ifc.MatrixContainer, mainView ifc.MainView, room *rooms.Room, evt *mautrix.Event) *UIMessage {
msg := directParseEvent(matrix, room, evt)
if msg == nil {
return nil
}
if len(evt.Content.GetReplyTo()) > 0 {
replyToRoom := room
if len(evt.Content.RelatesTo.InReplyTo.RoomID) > 0 {
replyToRoom = matrix.GetRoom(evt.Content.RelatesTo.InReplyTo.RoomID)
}
if replyToMsg := getCachedEvent(mainView, replyToRoom.ID, evt.Content.GetReplyTo()); replyToMsg != nil {
if replyToMsg := getCachedEvent(mainView, room.ID, evt.Content.GetReplyTo()); replyToMsg != nil {
replyToMsg = replyToMsg.Clone()
replyToMsg.SetReplyTo(nil)
msg.SetReplyTo(replyToMsg)
} else if replyToEvt, _ := matrix.GetEvent(replyToRoom, evt.Content.GetReplyTo()); replyToEvt != nil {
if replyToMsg := directParseEvent(matrix, replyToRoom, replyToEvt); replyToMsg != nil {
msg.SetReplyTo(replyToMsg)
replyToMsg.ReplyTo = nil
msg.ReplyTo = replyToMsg
} else if replyToEvt, _ := matrix.GetEvent(room, evt.Content.GetReplyTo()); replyToEvt != nil {
if replyToMsg := directParseEvent(matrix, room, replyToEvt); replyToMsg != nil {
msg.ReplyTo = replyToMsg
} else {
// TODO add unrenderable reply header
}
@ -70,15 +65,22 @@ func ParseEvent(matrix ifc.MatrixContainer, mainView ifc.MainView, room *rooms.R
return msg
}
func directParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) UIMessage {
func directParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) *UIMessage {
displayname := evt.Sender
member := room.GetMember(evt.Sender)
if member != nil {
displayname = member.Displayname
}
switch evt.Type {
case mautrix.EventSticker:
evt.Content.MsgType = mautrix.MsgImage
fallthrough
case mautrix.EventMessage:
return ParseMessage(matrix, room, evt)
return ParseMessage(matrix, room, evt, displayname)
case mautrix.EventEncrypted:
return NewExpandedTextMessage(evt, displayname, tstring.NewStyleTString("Encrypted messages are not yet supported", tcell.StyleDefault.Italic(true)))
case mautrix.StateTopic, mautrix.StateRoomName, mautrix.StateAliases, mautrix.StateCanonicalAlias:
return ParseStateEvent(matrix, room, evt)
return ParseStateEvent(evt, displayname)
case mautrix.StateMember:
return ParseMembershipEvent(room, evt)
}
@ -86,12 +88,7 @@ func directParseEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix
return nil
}
func ParseStateEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) UIMessage {
displayname := evt.Sender
member := room.GetMember(evt.Sender)
if member != nil {
displayname = member.Displayname
}
func ParseStateEvent(evt *mautrix.Event, displayname string) *UIMessage {
text := tstring.NewColorTString(displayname, widget.GetHashColor(evt.Sender))
switch evt.Type {
case mautrix.StateTopic:
@ -124,15 +121,13 @@ func ParseStateEvent(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.
return NewExpandedTextMessage(evt, displayname, text)
}
func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event) UIMessage {
displayname := evt.Sender
member := room.GetMember(evt.Sender)
if member != nil {
displayname = member.Displayname
}
func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *mautrix.Event, displayname string) *UIMessage {
if len(evt.Content.GetReplyTo()) > 0 {
evt.Content.RemoveReplyFallback()
}
if evt.Content.GetRelatesTo().Type == mautrix.RelReplace && evt.Content.NewContent != nil {
evt.Content = *evt.Content.NewContent
}
switch evt.Content.MsgType {
case "m.text", "m.notice", "m.emote":
if evt.Content.Format == mautrix.FormatHTML {
@ -224,7 +219,7 @@ func getMembershipEventContent(room *rooms.Room, evt *mautrix.Event) (sender str
return
}
func ParseMembershipEvent(room *rooms.Room, evt *mautrix.Event) UIMessage {
func ParseMembershipEvent(room *rooms.Room, evt *mautrix.Event) *UIMessage {
displayname, text := getMembershipEventContent(room, evt)
if len(text) == 0 {
return nil

View File

@ -52,12 +52,12 @@ func matchBoundaryPattern(bare bool, extract tstring.TString) tstring.TString {
// CalculateBuffer generates the internal buffer for this message that consists
// of the text of this message split into lines at most as wide as the width
// parameter.
func (msg *BaseMessage) calculateBufferWithText(prefs config.UserPreferences, text tstring.TString, width int) {
func calculateBufferWithText(prefs config.UserPreferences, text tstring.TString, width int, msg *UIMessage) []tstring.TString {
if width < 2 {
return
return nil
}
msg.buffer = []tstring.TString{}
var buffer []tstring.TString
if prefs.BareMessageView {
newText := tstring.NewTString(msg.FormatTime())
@ -74,7 +74,7 @@ func (msg *BaseMessage) calculateBufferWithText(prefs config.UserPreferences, te
newlines := 0
for _, str := range forcedLinebreaks {
if len(str) == 0 && newlines < 1 {
msg.buffer = append(msg.buffer, tstring.TString{})
buffer = append(buffer, tstring.TString{})
newlines++
} else {
newlines = 0
@ -88,8 +88,9 @@ func (msg *BaseMessage) calculateBufferWithText(prefs config.UserPreferences, te
}
extract = matchBoundaryPattern(prefs.BareMessageView, extract)
}
msg.buffer = append(msg.buffer, extract)
buffer = append(buffer, extract)
str = str[len(extract):]
}
}
return buffer
}

View File

@ -20,72 +20,82 @@ import (
"fmt"
"time"
ifc "maunium.net/go/gomuks/interface"
"maunium.net/go/mautrix"
"maunium.net/go/mauview"
"maunium.net/go/gomuks/config"
"maunium.net/go/gomuks/ui/messages/tstring"
)
type TextMessage struct {
BaseMessage
cache tstring.TString
MsgText string
cache tstring.TString
buffer []tstring.TString
Text string
}
// NewTextMessage creates a new UITextMessage object with the provided values and the default state.
func NewTextMessage(event *mautrix.Event, displayname string, text string) UIMessage {
return &TextMessage{
BaseMessage: newBaseMessage(event, displayname),
MsgText: text,
}
func NewTextMessage(event *mautrix.Event, displayname string, text string) *UIMessage {
return newUIMessage(event, displayname, &TextMessage{
Text: text,
})
}
func NewServiceMessage(text string) UIMessage {
return &TextMessage{
BaseMessage: BaseMessage{
MsgSenderID: "*",
MsgSender: "*",
MsgTimestamp: time.Now(),
MsgIsService: true,
func NewServiceMessage(text string) *UIMessage {
return &UIMessage{
SenderID: "*",
SenderName: "*",
Timestamp: time.Now(),
IsService: true,
Renderer: &TextMessage{
Text: text,
},
MsgText: text,
}
}
func (msg *TextMessage) Clone() UIMessage {
func (msg *TextMessage) Clone() MessageRenderer {
return &TextMessage{
BaseMessage: msg.BaseMessage.clone(),
MsgText: msg.MsgText,
Text: msg.Text,
}
}
func (msg *TextMessage) getCache() tstring.TString {
func (msg *TextMessage) getCache(uiMsg *UIMessage) tstring.TString {
if msg.cache == nil {
switch msg.MsgType {
switch uiMsg.Type {
case "m.emote":
msg.cache = tstring.NewColorTString(fmt.Sprintf("* %s %s", msg.MsgSender, msg.MsgText), msg.TextColor())
msg.cache.Colorize(0, len(msg.MsgSender)+2, msg.SenderColor())
msg.cache = tstring.NewColorTString(fmt.Sprintf("* %s %s", uiMsg.SenderName, msg.Text), uiMsg.TextColor())
msg.cache.Colorize(0, len(uiMsg.SenderName)+2, uiMsg.SenderColor())
default:
msg.cache = tstring.NewColorTString(msg.MsgText, msg.TextColor())
msg.cache = tstring.NewColorTString(msg.Text, uiMsg.TextColor())
}
}
return msg.cache
}
func (msg *TextMessage) SetIsHighlight(isHighlight bool) {
msg.BaseMessage.SetIsHighlight(isHighlight)
msg.cache = nil
}
func (msg *TextMessage) NotificationContent() string {
return msg.MsgText
return msg.Text
}
func (msg *TextMessage) PlainText() string {
return msg.MsgText
return msg.Text
}
func (msg *TextMessage) CalculateBuffer(prefs config.UserPreferences, width int) {
msg.CalculateReplyBuffer(prefs, width)
msg.calculateBufferWithText(prefs, msg.getCache(), width)
func (msg *TextMessage) String() string {
return fmt.Sprintf(`&messages.TextMessage{Text="%s"}`, msg.Text)
}
func (msg *TextMessage) CalculateBuffer(prefs config.UserPreferences, width int, uiMsg *UIMessage) {
msg.buffer = calculateBufferWithText(prefs, msg.getCache(uiMsg), width, uiMsg)
}
func (msg *TextMessage) Height() int {
return len(msg.buffer)
}
func (msg *TextMessage) Draw(screen mauview.Screen) {
for y, line := range msg.buffer {
line.Draw(screen, 0, y)
}
}
func (msg *TextMessage) RegisterMatrix(matrix ifc.MatrixContainer) {}