Refactoring and documentation
This commit is contained in:
parent
497ae566c0
commit
a9c899f0d5
@ -25,55 +25,176 @@ import (
|
|||||||
"github.com/mattn/go-runewidth"
|
"github.com/mattn/go-runewidth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MessageState is an enum to specify if a Message is being sent, failed to send or was successfully sent.
|
||||||
|
type MessageState int
|
||||||
|
|
||||||
|
// Allowed MessageStates.
|
||||||
|
const (
|
||||||
|
MessageStateSending MessageState = iota
|
||||||
|
MessageStateDefault
|
||||||
|
MessageStateFailed
|
||||||
|
)
|
||||||
|
|
||||||
|
// Message is a wrapper for the content and metadata of a Matrix message intended to be displayed.
|
||||||
type Message struct {
|
type Message struct {
|
||||||
BasicMeta
|
|
||||||
Type string
|
|
||||||
ID string
|
ID string
|
||||||
|
Type string
|
||||||
|
Sender string
|
||||||
|
SenderColor tcell.Color
|
||||||
|
Timestamp string
|
||||||
|
Date string
|
||||||
Text string
|
Text string
|
||||||
sending bool
|
State MessageState
|
||||||
buffer []string
|
buffer []string
|
||||||
prevBufferWidth int
|
prevBufferWidth int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewMessage creates a new Message object with the provided values and the default state.
|
||||||
func NewMessage(id, sender, msgtype, text, timestamp, date string, senderColor tcell.Color) *Message {
|
func NewMessage(id, sender, msgtype, text, timestamp, date string, senderColor tcell.Color) *Message {
|
||||||
return &Message{
|
return &Message{
|
||||||
BasicMeta: BasicMeta{
|
|
||||||
Sender: sender,
|
Sender: sender,
|
||||||
Timestamp: timestamp,
|
Timestamp: timestamp,
|
||||||
Date: date,
|
Date: date,
|
||||||
SenderColor: senderColor,
|
SenderColor: senderColor,
|
||||||
TextColor: tcell.ColorDefault,
|
|
||||||
TimestampColor: tcell.ColorDefault,
|
|
||||||
},
|
|
||||||
Type: msgtype,
|
Type: msgtype,
|
||||||
Text: text,
|
Text: text,
|
||||||
ID: id,
|
ID: id,
|
||||||
prevBufferWidth: 0,
|
prevBufferWidth: 0,
|
||||||
sending: false,
|
State: MessageStateDefault,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CopyTo copies the content of this message to the given message.
|
||||||
|
func (message *Message) CopyTo(to *Message) {
|
||||||
|
to.ID = message.ID
|
||||||
|
to.Type = message.Type
|
||||||
|
to.Sender = message.Sender
|
||||||
|
to.SenderColor = message.SenderColor
|
||||||
|
to.Timestamp = message.Timestamp
|
||||||
|
to.Date = message.Date
|
||||||
|
to.Text = message.Text
|
||||||
|
to.RecalculateBuffer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSender 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 (message *Message) GetSender() string {
|
||||||
|
switch message.State {
|
||||||
|
case MessageStateSending:
|
||||||
|
return "Sending..."
|
||||||
|
case MessageStateFailed:
|
||||||
|
return "Error"
|
||||||
|
}
|
||||||
|
switch message.Type {
|
||||||
|
case "m.emote":
|
||||||
|
// Emotes don't show a separate sender, it's included in the buffer.
|
||||||
|
return ""
|
||||||
|
default:
|
||||||
|
return message.Sender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSenderColor returns the color the name of the sender should be shown in.
|
||||||
|
//
|
||||||
|
// If the message is being sent, the color is gray.
|
||||||
|
// If sending has failed, the color is red.
|
||||||
|
//
|
||||||
|
// 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 (message *Message) GetSenderColor() tcell.Color {
|
||||||
|
switch message.State {
|
||||||
|
case MessageStateSending:
|
||||||
|
return tcell.ColorGray
|
||||||
|
case MessageStateFailed:
|
||||||
|
return tcell.ColorRed
|
||||||
|
case MessageStateDefault:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
return message.SenderColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTextColor returns the color the actual content of the message should be shown in.
|
||||||
|
//
|
||||||
|
// As with GetSenderColor(), messages being sent and messages that failed to be sent are
|
||||||
|
// gray and red respectively.
|
||||||
|
//
|
||||||
|
// However, other messages are the default color instead of a color stored in the struct.
|
||||||
|
func (message *Message) GetTextColor() tcell.Color {
|
||||||
|
switch message.State {
|
||||||
|
case MessageStateSending:
|
||||||
|
return tcell.ColorGray
|
||||||
|
case MessageStateFailed:
|
||||||
|
return tcell.ColorRed
|
||||||
|
default:
|
||||||
|
return tcell.ColorDefault
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTimestampColor returns the color the timestamp should be shown in.
|
||||||
|
//
|
||||||
|
// Currently, this simply calls GetTextColor().
|
||||||
|
func (message *Message) GetTimestampColor() tcell.Color {
|
||||||
|
return message.GetTextColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecalculateBuffer calculates the buffer again with the previously provided width.
|
||||||
|
func (message *Message) RecalculateBuffer() {
|
||||||
|
message.CalculateBuffer(message.prevBufferWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (message *Message) Buffer() []string {
|
||||||
|
return message.buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Height returns the number of rows in the computed buffer (see Buffer()).
|
||||||
|
func (message *Message) Height() int {
|
||||||
|
return len(message.buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTimestamp returns the formatted time when the message was sent.
|
||||||
|
func (message *Message) GetTimestamp() string {
|
||||||
|
return message.Timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDate returns the formatted date when the message was sent.
|
||||||
|
func (message *Message) GetDate() string {
|
||||||
|
return message.Date
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular expressions used to split lines when calculating the buffer.
|
||||||
|
//
|
||||||
|
// From tview/textview.go
|
||||||
var (
|
var (
|
||||||
boundaryPattern = regexp.MustCompile("([[:punct:]]\\s*|\\s+)")
|
boundaryPattern = regexp.MustCompile("([[:punct:]]\\s*|\\s+)")
|
||||||
spacePattern = regexp.MustCompile(`\s+`)
|
spacePattern = regexp.MustCompile(`\s+`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (message *Message) CopyTo(to *Message) {
|
// CalculateBuffer generates the internal buffer for this message that consists
|
||||||
to.BasicMeta = message.BasicMeta
|
// of the text of this message split into lines at most as wide as the width
|
||||||
to.ID = message.ID
|
// parameter.
|
||||||
to.Text = message.Text
|
|
||||||
to.RecalculateBuffer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (message *Message) CalculateBuffer(width int) {
|
func (message *Message) CalculateBuffer(width int) {
|
||||||
if width < 2 {
|
if width < 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
message.buffer = []string{}
|
message.buffer = []string{}
|
||||||
text := message.Text
|
text := message.Text
|
||||||
if message.Type == "m.emote" {
|
if message.Type == "m.emote" {
|
||||||
text = fmt.Sprintf("* %s %s", message.Sender, message.Text)
|
text = fmt.Sprintf("* %s %s", message.Sender, message.Text)
|
||||||
}
|
}
|
||||||
|
|
||||||
forcedLinebreaks := strings.Split(text, "\n")
|
forcedLinebreaks := strings.Split(text, "\n")
|
||||||
newlines := 0
|
newlines := 0
|
||||||
for _, str := range forcedLinebreaks {
|
for _, str := range forcedLinebreaks {
|
||||||
@ -102,31 +223,3 @@ func (message *Message) CalculateBuffer(width int) {
|
|||||||
}
|
}
|
||||||
message.prevBufferWidth = width
|
message.prevBufferWidth = width
|
||||||
}
|
}
|
||||||
|
|
||||||
func (message *Message) GetDisplaySender() string {
|
|
||||||
if message.sending {
|
|
||||||
return "Sending..."
|
|
||||||
}
|
|
||||||
switch message.Type {
|
|
||||||
case "m.emote":
|
|
||||||
return ""
|
|
||||||
default:
|
|
||||||
return message.Sender
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (message *Message) SetIsSending(sending bool) {
|
|
||||||
message.sending = sending
|
|
||||||
}
|
|
||||||
|
|
||||||
func (message *Message) RecalculateBuffer() {
|
|
||||||
message.CalculateBuffer(message.prevBufferWidth)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (message *Message) Buffer() []string {
|
|
||||||
return message.buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (message *Message) Height() int {
|
|
||||||
return len(message.buffer)
|
|
||||||
}
|
|
||||||
|
@ -20,9 +20,11 @@ import (
|
|||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MessageMeta is an interface to get the metadata of a message.
|
||||||
|
//
|
||||||
|
// See BasicMeta for a simple implementation and documentation of methods.
|
||||||
type MessageMeta interface {
|
type MessageMeta interface {
|
||||||
GetSender() string
|
GetSender() string
|
||||||
GetDisplaySender() string
|
|
||||||
GetSenderColor() tcell.Color
|
GetSenderColor() tcell.Color
|
||||||
GetTextColor() tcell.Color
|
GetTextColor() tcell.Color
|
||||||
GetTimestampColor() tcell.Color
|
GetTimestampColor() tcell.Color
|
||||||
@ -30,35 +32,40 @@ type MessageMeta interface {
|
|||||||
GetDate() string
|
GetDate() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BasicMeta is a simple variable store implementation of MessageMeta.
|
||||||
type BasicMeta struct {
|
type BasicMeta struct {
|
||||||
Sender, Timestamp, Date string
|
Sender, Timestamp, Date string
|
||||||
SenderColor, TextColor, TimestampColor tcell.Color
|
SenderColor, TextColor, TimestampColor tcell.Color
|
||||||
}
|
}
|
||||||
|
|
||||||
func (meta *BasicMeta) GetDisplaySender() string {
|
// GetSender gets the string that should be displayed as the sender of this message.
|
||||||
return meta.Sender
|
|
||||||
}
|
|
||||||
|
|
||||||
func (meta *BasicMeta) GetSender() string {
|
func (meta *BasicMeta) GetSender() string {
|
||||||
return meta.Sender
|
return meta.Sender
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSenderColor returns the color the name of the sender should be shown in.
|
||||||
func (meta *BasicMeta) GetSenderColor() tcell.Color {
|
func (meta *BasicMeta) GetSenderColor() tcell.Color {
|
||||||
return meta.SenderColor
|
return meta.SenderColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTimestamp returns the formatted time when the message was sent.
|
||||||
func (meta *BasicMeta) GetTimestamp() string {
|
func (meta *BasicMeta) GetTimestamp() string {
|
||||||
return meta.Timestamp
|
return meta.Timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDate returns the formatted date when the message was sent.
|
||||||
func (meta *BasicMeta) GetDate() string {
|
func (meta *BasicMeta) GetDate() string {
|
||||||
return meta.Date
|
return meta.Date
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTextColor returns the color the actual content of the message should be shown in.
|
||||||
func (meta *BasicMeta) GetTextColor() tcell.Color {
|
func (meta *BasicMeta) GetTextColor() tcell.Color {
|
||||||
return meta.TextColor
|
return meta.TextColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTimestampColor 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) GetTimestampColor() tcell.Color {
|
func (meta *BasicMeta) GetTimestampColor() tcell.Color {
|
||||||
return meta.TimestampColor
|
return meta.TimestampColor
|
||||||
}
|
}
|
||||||
|
@ -315,7 +315,6 @@ func (view *MessageView) Draw(screen tcell.Screen) {
|
|||||||
screen.SetContent(separatorX, separatorY, view.Separator, nil, tcell.StyleDefault)
|
screen.SetContent(separatorX, separatorY, view.Separator, nil, tcell.StyleDefault)
|
||||||
}
|
}
|
||||||
|
|
||||||
var prevMeta types.MessageMeta
|
|
||||||
indexOffset := len(view.textBuffer) - view.ScrollOffset - height
|
indexOffset := len(view.textBuffer) - view.ScrollOffset - height
|
||||||
if indexOffset <= -PaddingAtTop {
|
if indexOffset <= -PaddingAtTop {
|
||||||
message := "Scroll up to load more messages."
|
message := "Scroll up to load more messages."
|
||||||
@ -324,10 +323,13 @@ func (view *MessageView) Draw(screen tcell.Screen) {
|
|||||||
}
|
}
|
||||||
view.writeLine(screen, message, x+messageOffsetX, y, tcell.ColorGreen)
|
view.writeLine(screen, message, x+messageOffsetX, y, tcell.ColorGreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(view.textBuffer) != len(view.metaBuffer) {
|
if len(view.textBuffer) != len(view.metaBuffer) {
|
||||||
debug.ExtPrintf("Unexpected text/meta buffer length mismatch: %d != %d.", len(view.textBuffer), len(view.metaBuffer))
|
debug.ExtPrintf("Unexpected text/meta buffer length mismatch: %d != %d.", len(view.textBuffer), len(view.metaBuffer))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var prevMeta types.MessageMeta
|
||||||
for line := 0; line < height; line++ {
|
for line := 0; line < height; line++ {
|
||||||
index := indexOffset + line
|
index := indexOffset + line
|
||||||
if index < 0 {
|
if index < 0 {
|
||||||
@ -342,7 +344,7 @@ func (view *MessageView) Draw(screen tcell.Screen) {
|
|||||||
}
|
}
|
||||||
if prevMeta == nil || meta.GetSender() != prevMeta.GetSender() {
|
if prevMeta == nil || meta.GetSender() != prevMeta.GetSender() {
|
||||||
view.writeLineRight(
|
view.writeLineRight(
|
||||||
screen, meta.GetDisplaySender(),
|
screen, meta.GetSender(),
|
||||||
x+usernameOffsetX, y+line,
|
x+usernameOffsetX, y+line,
|
||||||
view.widestSender, meta.GetSenderColor())
|
view.widestSender, meta.GetSenderColor())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user