Add support for m.emote. Fixes #6

This commit is contained in:
Tulir Asokan 2018-03-22 21:44:46 +02:00
parent 702a75a8c0
commit 152b89ed5e
9 changed files with 102 additions and 53 deletions

View File

@ -28,7 +28,7 @@ type MatrixContainer interface {
Login(user, password string) error
Start()
Stop()
SendMessage(roomID, message string) (string, error)
SendMessage(roomID, msgtype, message string) (string, error)
SendTyping(roomID string, typing bool)
JoinRoom(roomID string) error
LeaveRoom(roomID string) error

View File

@ -47,7 +47,7 @@ type MainView interface {
SaveAllHistory()
SetTyping(roomID string, users []string)
AddServiceMessage(roomID string, message string)
AddServiceMessage(roomID *widget.RoomView, message string)
ProcessMessageEvent(evt *gomatrix.Event) (*widget.RoomView, *types.Message)
ProcessMembershipEvent(evt *gomatrix.Event, new bool) (*widget.RoomView, *types.Message)
}

View File

@ -280,10 +280,11 @@ func (c *Container) HandleTyping(evt *gomatrix.Event) {
}
// SendMessage sends a message with the given text to the given room.
func (c *Container) SendMessage(roomID, text string) (string, error) {
func (c *Container) SendMessage(roomID, msgtype, text string) (string, error) {
defer c.gmx.Recover()
c.SendTyping(roomID, false)
resp, err := c.client.SendText(roomID, text)
resp, err := c.client.SendMessageEvent(roomID, "m.room.message",
gomatrix.TextMessage{MsgType: msgtype, Body: text})
if err != nil {
return "", err
}

View File

@ -225,6 +225,11 @@ func (room *Room) GetMember(userID string) *Member {
return member
}
// GetSessionOwner returns the Member instance of the user whose session this room was created for.
func (room *Room) GetSessionOwner() *Member {
return room.GetMember(room.SessionUserID)
}
// NewRoom creates a new Room with the given ID
func NewRoom(roomID, owner string) *Room {
return &Room{

View File

@ -17,6 +17,7 @@
package types
import (
"fmt"
"regexp"
"strings"
@ -26,13 +27,15 @@ import (
type Message struct {
BasicMeta
Type string
ID string
Text string
sending bool
buffer []string
prevBufferWidth int
}
func NewMessage(id, sender, text, timestamp, date string, senderColor tcell.Color) *Message {
func NewMessage(id, sender, msgtype, text, timestamp, date string, senderColor tcell.Color) *Message {
return &Message{
BasicMeta: BasicMeta{
Sender: sender,
@ -42,9 +45,11 @@ func NewMessage(id, sender, text, timestamp, date string, senderColor tcell.Colo
TextColor: tcell.ColorDefault,
TimestampColor: tcell.ColorDefault,
},
Type: msgtype,
Text: text,
ID: id,
prevBufferWidth: 0,
sending: false,
}
}
@ -65,7 +70,11 @@ func (message *Message) CalculateBuffer(width int) {
return
}
message.buffer = []string{}
forcedLinebreaks := strings.Split(message.Text, "\n")
text := message.Text
if message.Type == "m.emote" {
text = fmt.Sprintf("* %s %s", message.Sender, message.Text)
}
forcedLinebreaks := strings.Split(text, "\n")
newlines := 0
for _, str := range forcedLinebreaks {
if len(str) == 0 && newlines < 1 {
@ -94,6 +103,22 @@ func (message *Message) CalculateBuffer(width int) {
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)
}

View File

@ -22,6 +22,7 @@ import (
type MessageMeta interface {
GetSender() string
GetDisplaySender() string
GetSenderColor() tcell.Color
GetTextColor() tcell.Color
GetTimestampColor() tcell.Color
@ -34,6 +35,10 @@ type BasicMeta struct {
SenderColor, TextColor, TimestampColor tcell.Color
}
func (meta *BasicMeta) GetDisplaySender() string {
return meta.Sender
}
func (meta *BasicMeta) GetSender() string {
return meta.Sender
}

View File

@ -19,7 +19,6 @@ package ui
import (
"fmt"
"sort"
"strconv"
"strings"
"time"
"unicode"
@ -123,42 +122,40 @@ func (view *MainView) InputSubmit(roomView *widget.RoomView, text string) {
args := strings.SplitN(text, " ", 2)
command := strings.ToLower(args[0])
args = args[1:]
go view.HandleCommand(roomView.Room.ID, command, args)
go view.HandleCommand(roomView, command, args)
} else {
view.SendMessage(roomView.Room.ID, text)
view.SendMessage(roomView, text)
}
roomView.SetInputText("")
}
func (view *MainView) SendMessage(room, text string) {
now := time.Now()
roomView := view.GetRoom(room)
tempMessage := roomView.NewMessage(
strconv.FormatInt(now.UnixNano(), 10),
"Sending...", text, now)
tempMessage.TimestampColor = tcell.ColorGray
tempMessage.TextColor = tcell.ColorGray
tempMessage.SenderColor = tcell.ColorGray
roomView.AddMessage(tempMessage, widget.AppendMessage)
go func() {
defer view.gmx.Recover()
eventID, err := view.matrix.SendMessage(room, text)
if err != nil {
tempMessage.TextColor = tcell.ColorRed
tempMessage.TimestampColor = tcell.ColorRed
tempMessage.SenderColor = tcell.ColorRed
tempMessage.Sender = "Error"
roomView.SetStatus(fmt.Sprintf("Failed to send message: %s", err))
} else {
roomView.MessageView().UpdateMessageID(tempMessage, eventID)
}
}()
func (view *MainView) SendMessage(roomView *widget.RoomView, text string) {
tempMessage := roomView.NewTempMessage("m.text", text)
go view.sendTempMessage(roomView, tempMessage)
}
func (view *MainView) HandleCommand(room, command string, args []string) {
func (view *MainView) sendTempMessage(roomView *widget.RoomView, tempMessage *types.Message) {
defer view.gmx.Recover()
eventID, err := view.matrix.SendMessage(roomView.Room.ID, tempMessage.Type, tempMessage.Text)
if err != nil {
tempMessage.TextColor = tcell.ColorRed
tempMessage.TimestampColor = tcell.ColorRed
tempMessage.SenderColor = tcell.ColorRed
tempMessage.Sender = "Error"
roomView.SetStatus(fmt.Sprintf("Failed to send message: %s", err))
} else {
roomView.MessageView().UpdateMessageID(tempMessage, eventID)
}
}
func (view *MainView) HandleCommand(roomView *widget.RoomView, command string, args []string) {
defer view.gmx.Recover()
debug.Print("Handling command", command, args)
switch command {
case "/me":
tempMessage := roomView.NewTempMessage("m.emote", strings.Join(args, " "))
go view.sendTempMessage(roomView, tempMessage)
view.parent.Render()
case "/quit":
view.gmx.Stop()
case "/clearcache":
@ -169,15 +166,15 @@ func (view *MainView) HandleCommand(room, command string, args []string) {
case "/part":
fallthrough
case "/leave":
debug.Print(view.matrix.LeaveRoom(room))
debug.Print("Leave room result:", view.matrix.LeaveRoom(roomView.Room.ID))
case "/join":
if len(args) == 0 {
view.AddServiceMessage(room, "Usage: /join <room>")
view.AddServiceMessage(roomView, "Usage: /join <room>")
break
}
debug.Print(view.matrix.JoinRoom(args[0]))
debug.Print("Join room result:", view.matrix.JoinRoom(args[0]))
default:
view.AddServiceMessage(room, "Unknown command.")
view.AddServiceMessage(roomView, "Unknown command.")
}
}
@ -331,13 +328,12 @@ func (view *MainView) SetTyping(room string, users []string) {
}
}
func (view *MainView) AddServiceMessage(room, message string) {
roomView, ok := view.rooms[room]
if ok {
message := roomView.NewMessage("", "*", message, time.Now())
roomView.AddMessage(message, widget.AppendMessage)
view.parent.Render()
}
func (view *MainView) AddServiceMessage(roomView *widget.RoomView, text string) {
message := roomView.NewMessage("", "*", "gomuks.service", text, time.Now())
message.TextColor = tcell.ColorGray
message.SenderColor = tcell.ColorGray
roomView.AddMessage(message, widget.AppendMessage)
view.parent.Render()
}
func (view *MainView) LoadMoreHistory(room string) {
@ -375,7 +371,7 @@ func (view *MainView) LoadHistory(room string, initial bool) {
debug.Print("Loading history for", room, "starting from", batch, "(initial:", initial, ")")
history, prevBatch, err := view.matrix.GetHistory(roomView.Room.ID, batch, 50)
if err != nil {
view.AddServiceMessage(room, "Failed to fetch history")
view.AddServiceMessage(roomView, "Failed to fetch history")
debug.Print("Failed to fetch history for", roomView.Room.ID, err)
return
}
@ -404,7 +400,8 @@ func (view *MainView) ProcessMessageEvent(evt *gomatrix.Event) (room *widget.Roo
room = view.GetRoom(evt.RoomID)
if room != nil {
text, _ := evt.Content["body"].(string)
message = room.NewMessage(evt.ID, evt.Sender, text, unixToTime(evt.Timestamp))
msgtype, _ := evt.Content["msgtype"].(string)
message = room.NewMessage(evt.ID, evt.Sender, msgtype, text, unixToTime(evt.Timestamp))
}
return
}
@ -452,7 +449,7 @@ func (view *MainView) ProcessMembershipEvent(evt *gomatrix.Event, new bool) (roo
room = nil
return
}
message = room.NewMessage(evt.ID, sender, text, unixToTime(evt.Timestamp))
message = room.NewMessage(evt.ID, sender, "m.room.member", text, unixToTime(evt.Timestamp))
message.TextColor = tcell.ColorGreen
}
return

View File

@ -74,8 +74,8 @@ func NewMessageView() *MessageView {
}
}
func (view *MessageView) NewMessage(id, sender, text string, timestamp time.Time) *types.Message {
return types.NewMessage(id, sender, text,
func (view *MessageView) NewMessage(id, sender, msgtype, text string, timestamp time.Time) *types.Message {
return types.NewMessage(id, sender, msgtype, text,
timestamp.Format(view.TimestampFormat),
timestamp.Format(view.DateFormat),
GetHashColor(sender))
@ -151,6 +151,8 @@ func (view *MessageView) AddMessage(message *types.Message, direction MessageDir
msg, messageExists := view.messageIDs[message.ID]
if msg != nil && messageExists {
message.CopyTo(msg)
message = msg
message.SetIsSending(false)
direction = IgnoreMessage
}
@ -338,9 +340,9 @@ func (view *MessageView) Draw(screen tcell.Screen) {
if len(meta.GetTimestamp()) > 0 {
view.writeLine(screen, meta.GetTimestamp(), x, y+line, meta.GetTimestampColor())
}
if len(meta.GetSender()) > 0 && (prevMeta == nil || meta.GetSender() != prevMeta.GetSender()) {
if prevMeta == nil || meta.GetSender() != prevMeta.GetSender() {
view.writeLineRight(
screen, meta.GetSender(),
screen, meta.GetDisplaySender(),
x+usernameOffsetX, y+line,
view.widestSender, meta.GetSenderColor())
}

View File

@ -19,6 +19,7 @@ package widget
import (
"fmt"
"path/filepath"
"strconv"
"strings"
"time"
@ -239,12 +240,25 @@ func (view *RoomView) UpdateUserList() {
}
}
func (view *RoomView) NewMessage(id, sender, text string, timestamp time.Time) *types.Message {
func (view *RoomView) NewMessage(id, sender, msgtype, text string, timestamp time.Time) *types.Message {
member := view.Room.GetMember(sender)
if member != nil {
sender = member.DisplayName
}
return view.content.NewMessage(id, sender, text, timestamp)
return view.content.NewMessage(id, sender, msgtype, text, timestamp)
}
func (view *RoomView) NewTempMessage(msgtype, text string) *types.Message {
now := time.Now()
id := strconv.FormatInt(now.UnixNano(), 10)
sender := view.Room.GetSessionOwner().DisplayName
message := view.NewMessage(id, sender, msgtype, text, now)
message.SetIsSending(true)
message.TimestampColor = tcell.ColorGray
message.TextColor = tcell.ColorGray
message.SenderColor = tcell.ColorGray
view.AddMessage(message, AppendMessage)
return message
}
func (view *RoomView) AddMessage(message *types.Message, direction MessageDirection) {