diff --git a/interface/matrix.go b/interface/matrix.go index 4c30b5e..c40639d 100644 --- a/interface/matrix.go +++ b/interface/matrix.go @@ -28,10 +28,7 @@ type MatrixContainer interface { Login(user, password string) error Start() Stop() - // HandleMessage(evt *gomatrix.Event) - // HandleMembership(evt *gomatrix.Event) - // HandleTyping(evt *gomatrix.Event) - SendMessage(roomID, message string) + SendMessage(roomID, message string) (string, error) SendTyping(roomID string, typing bool) JoinRoom(roomID string) error LeaveRoom(roomID string) error diff --git a/matrix/matrix.go b/matrix/matrix.go index f20825c..d7e9ed3 100644 --- a/matrix/matrix.go +++ b/matrix/matrix.go @@ -213,10 +213,14 @@ func (c *Container) HandleTyping(evt *gomatrix.Event) { c.ui.MainView().SetTyping(evt.RoomID, strUsers) } -func (c *Container) SendMessage(roomID, message string) { +func (c *Container) SendMessage(roomID, text string) (string, error) { defer c.gmx.Recover() c.SendTyping(roomID, false) - c.client.SendText(roomID, message) + resp, err := c.client.SendText(roomID, text) + if err != nil { + return "", err + } + return resp.EventID, nil } func (c *Container) SendTyping(roomID string, typing bool) { @@ -250,8 +254,6 @@ func (c *Container) JoinRoom(roomID string) error { return err } - // TODO probably safe to remove - // c.ui.MainView().AddRoom(resp.RoomID) return nil } diff --git a/ui/types/message.go b/ui/types/message.go index 8899a7d..7b96193 100644 --- a/ui/types/message.go +++ b/ui/types/message.go @@ -25,24 +25,26 @@ import ( ) type Message struct { - ID string - Sender string - Text string - Timestamp string - Date string - - Buffer []string - SenderColor tcell.Color + BasicMeta + ID string + Text string + Buffer []string + prevBufferWidth int } func NewMessage(id, sender, text, timestamp, date string, senderColor tcell.Color) *Message { return &Message{ - ID: id, - Sender: sender, - Text: text, - Timestamp: timestamp, - Date: date, - SenderColor: senderColor, + BasicMeta: BasicMeta{ + Sender: sender, + Timestamp: timestamp, + Date: date, + SenderColor: senderColor, + TextColor: tcell.ColorDefault, + TimestampColor: tcell.ColorDefault, + }, + Text: text, + ID: id, + prevBufferWidth: 0, } } @@ -51,6 +53,13 @@ var ( spacePattern = regexp.MustCompile(`\s+`) ) +func (message *Message) CopyTo(to *Message) { + to.BasicMeta = message.BasicMeta + to.ID = message.ID + to.Text = message.Text + to.RecalculateBuffer() +} + func (message *Message) CalculateBuffer(width int) { if width < 1 { return @@ -82,28 +91,9 @@ func (message *Message) CalculateBuffer(width int) { str = str[len(extract):] } } + message.prevBufferWidth = width } -func (message *Message) GetSender() string { - return message.Sender -} - -func (message *Message) GetSenderColor() tcell.Color { - return message.SenderColor -} - -func (message *Message) GetTimestamp() string { - return message.Timestamp -} - -func (message *Message) GetDate() string { - return message.Date -} - -func (message *Message) GetTextColor() tcell.Color { - return tcell.ColorDefault -} - -func (message *Message) GetTimestampColor() tcell.Color { - return tcell.ColorDefault +func (message *Message) RecalculateBuffer() { + message.CalculateBuffer(message.prevBufferWidth) } diff --git a/ui/view-main.go b/ui/view-main.go index 707fd95..01ea7a1 100644 --- a/ui/view-main.go +++ b/ui/view-main.go @@ -19,6 +19,7 @@ package ui import ( "fmt" "sort" + "strconv" "strings" "time" "unicode" @@ -122,7 +123,7 @@ func (view *MainView) InputTabComplete(text string, cursorOffset int) string { word := findWordToTabComplete(str) userCompletions := roomView.AutocompleteUser(word) if len(userCompletions) == 1 { - startIndex := len(str)-len(word) + startIndex := len(str) - len(word) completion := userCompletions[0] if startIndex == 0 { completion = completion + ": " @@ -136,20 +137,46 @@ func (view *MainView) InputTabComplete(text string, cursorOffset int) string { } func (view *MainView) InputDone(key tcell.Key) { - if key == tcell.KeyEnter { - room, text := view.CurrentRoomID(), view.input.GetText() - if len(text) == 0 { - return - } else if text[0] == '/' { - args := strings.SplitN(text, " ", 2) - command := strings.ToLower(args[0]) - args = args[1:] - go view.HandleCommand(room, command, args) - } else { - go view.matrix.SendMessage(room, text) - } - view.input.SetText("") + if key != tcell.KeyEnter { + return } + room, text := view.CurrentRoomID(), view.input.GetText() + if len(text) == 0 { + return + } else if text[0] == '/' { + args := strings.SplitN(text, " ", 2) + command := strings.ToLower(args[0]) + args = args[1:] + go view.HandleCommand(room, command, args) + } else { + view.SendMessage(room, text) + } + view.input.SetText("") +} + +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) HandleCommand(room, command string, args []string) { @@ -418,6 +445,7 @@ func (view *MainView) ProcessMembershipEvent(evt *gomatrix.Event, new bool) (roo return } message = room.NewMessage(evt.ID, sender, text, unixToTime(evt.Timestamp)) + message.TextColor = tcell.ColorGreen } return } diff --git a/ui/widget/message-view.go b/ui/widget/message-view.go index 14d026a..78d37c1 100644 --- a/ui/widget/message-view.go +++ b/ui/widget/message-view.go @@ -42,7 +42,7 @@ type MessageView struct { prevHeight int prevMsgCount int - messageIDs map[string]bool + messageIDs map[string]*types.Message messages []*types.Message textBuffer []string @@ -60,7 +60,7 @@ func NewMessageView() *MessageView { ScrollOffset: 0, messages: make([]*types.Message, 0), - messageIDs: make(map[string]bool), + messageIDs: make(map[string]*types.Message), textBuffer: make([]string, 0), metaBuffer: make([]types.MessageMeta, 0), @@ -87,15 +87,25 @@ func (view *MessageView) updateWidestSender(sender string) { } } +type MessageDirection int + const ( - AppendMessage = iota + AppendMessage MessageDirection = iota PrependMessage + IgnoreMessage ) -func (view *MessageView) AddMessage(message *types.Message, direction int) { - _, messageExists := view.messageIDs[message.ID] +func (view *MessageView) UpdateMessageID(message *types.Message, newID string) { + delete(view.messageIDs, message.ID) + message.ID = newID + view.messageIDs[message.ID] = message +} + +func (view *MessageView) AddMessage(message *types.Message, direction MessageDirection) { + msg, messageExists := view.messageIDs[message.ID] if messageExists { - return + message.CopyTo(msg) + direction = IgnoreMessage } view.updateWidestSender(message.Sender) @@ -114,7 +124,7 @@ func (view *MessageView) AddMessage(message *types.Message, direction int) { view.messages = append([]*types.Message{message}, view.messages...) } - view.messageIDs[message.ID] = true + view.messageIDs[message.ID] = message } func (view *MessageView) appendBuffer(message *types.Message) { diff --git a/ui/widget/room-view.go b/ui/widget/room-view.go index 316fcef..b103490 100644 --- a/ui/widget/room-view.go +++ b/ui/widget/room-view.go @@ -147,6 +147,6 @@ func (view *RoomView) NewMessage(id, sender, text string, timestamp time.Time) * return view.content.NewMessage(id, sender, text, timestamp) } -func (view *RoomView) AddMessage(message *types.Message, direction int) { +func (view *RoomView) AddMessage(message *types.Message, direction MessageDirection) { view.content.AddMessage(message, direction) }