diff options
author | Tulir Asokan <tulir@maunium.net> | 2018-03-22 21:44:46 +0200 |
---|---|---|
committer | Tulir Asokan <tulir@maunium.net> | 2018-03-22 21:45:02 +0200 |
commit | 152b89ed5e6a4a3edbfc40222b4388049a213b82 (patch) | |
tree | e8507622e14f873128dd457b0f95f13cc460b459 | |
parent | 702a75a8c0355737e3e62735b59fe30bee7e42f4 (diff) |
Add support for m.emote. Fixes #6
-rw-r--r-- | interface/matrix.go | 2 | ||||
-rw-r--r-- | interface/ui.go | 2 | ||||
-rw-r--r-- | matrix/matrix.go | 5 | ||||
-rw-r--r-- | matrix/room/room.go | 5 | ||||
-rw-r--r-- | ui/types/message.go | 29 | ||||
-rw-r--r-- | ui/types/meta.go | 5 | ||||
-rw-r--r-- | ui/view-main.go | 79 | ||||
-rw-r--r-- | ui/widget/message-view.go | 10 | ||||
-rw-r--r-- | ui/widget/room-view.go | 18 |
9 files changed, 102 insertions, 53 deletions
diff --git a/interface/matrix.go b/interface/matrix.go index 459f99d..4202ebf 100644 --- a/interface/matrix.go +++ b/interface/matrix.go @@ -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 diff --git a/interface/ui.go b/interface/ui.go index bded310..9b2d0f1 100644 --- a/interface/ui.go +++ b/interface/ui.go @@ -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) } diff --git a/matrix/matrix.go b/matrix/matrix.go index a73e050..19bc226 100644 --- a/matrix/matrix.go +++ b/matrix/matrix.go @@ -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 } diff --git a/matrix/room/room.go b/matrix/room/room.go index c006bd3..4166fd7 100644 --- a/matrix/room/room.go +++ b/matrix/room/room.go @@ -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{ diff --git a/ui/types/message.go b/ui/types/message.go index e6ded4a..5cbc61d 100644 --- a/ui/types/message.go +++ b/ui/types/message.go @@ -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) } diff --git a/ui/types/meta.go b/ui/types/meta.go index c1817d4..03e18d6 100644 --- a/ui/types/meta.go +++ b/ui/types/meta.go @@ -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 } diff --git a/ui/view-main.go b/ui/view-main.go index 36ffe28..50a6cdb 100644 --- a/ui/view-main.go +++ b/ui/view-main.go @@ -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) 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(room, command string, args []string) { +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 diff --git a/ui/widget/message-view.go b/ui/widget/message-view.go index fe906b5..a4ba236 100644 --- a/ui/widget/message-view.go +++ b/ui/widget/message-view.go @@ -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()) } diff --git a/ui/widget/room-view.go b/ui/widget/room-view.go index 141e993..7e01fd4 100644 --- a/ui/widget/room-view.go +++ b/ui/widget/room-view.go @@ -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) { |