aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface/matrix.go3
-rw-r--r--interface/ui.go2
-rw-r--r--matrix/matrix.go12
-rw-r--r--ui/message-view.go28
-rw-r--r--ui/messages/expandedtextmessage.go86
-rw-r--r--ui/messages/imagemessage.go42
-rw-r--r--ui/messages/message.go1
-rw-r--r--ui/messages/parser.go10
-rw-r--r--ui/messages/textmessage.go62
-rw-r--r--ui/room-view.go4
-rw-r--r--ui/view-main.go20
11 files changed, 181 insertions, 89 deletions
diff --git a/interface/matrix.go b/interface/matrix.go
index cf011cf..3a1ec14 100644
--- a/interface/matrix.go
+++ b/interface/matrix.go
@@ -34,5 +34,6 @@ type MatrixContainer interface {
LeaveRoom(roomID string) error
GetHistory(roomID, prevBatch string, limit int) ([]gomatrix.Event, string, error)
GetRoom(roomID string) *rooms.Room
- Download(mxcURL string) ([]byte, string, error)
+ Download(mxcURL string) ([]byte, string, string, error)
+ GetCachePath(homeserver, fileID string) string
}
diff --git a/interface/ui.go b/interface/ui.go
index 8d3836d..fed1a73 100644
--- a/interface/ui.go
+++ b/interface/ui.go
@@ -71,7 +71,7 @@ const (
type RoomView interface {
MxRoom() *rooms.Room
SaveHistory(dir string) error
- LoadHistory(dir string) (int, error)
+ LoadHistory(gmx Gomuks, dir string) (int, error)
SetStatus(status string)
SetTyping(users []string)
diff --git a/matrix/matrix.go b/matrix/matrix.go
index b4d5775..48bb57f 100644
--- a/matrix/matrix.go
+++ b/matrix/matrix.go
@@ -413,17 +413,16 @@ func (c *Container) GetRoom(roomID string) *rooms.Room {
var mxcRegex = regexp.MustCompile("mxc://(.+)/(.+)")
-func (c *Container) Download(mxcURL string) (data []byte, fullID string, err error) {
+func (c *Container) Download(mxcURL string) (data []byte, hs, id string, err error) {
parts := mxcRegex.FindStringSubmatch(mxcURL)
if parts == nil || len(parts) != 3 {
err = fmt.Errorf("invalid matrix content URL")
return
}
- hs := parts[1]
- id := parts[2]
- fullID = fmt.Sprintf("%s/%s", hs, id)
+ hs = parts[1]
+ id = parts[2]
- cacheFile := c.getCachePath(hs, id)
+ cacheFile := c.GetCachePath(hs, id)
if _, err = os.Stat(cacheFile); err != nil {
data, err = ioutil.ReadFile(cacheFile)
if err == nil {
@@ -452,7 +451,8 @@ func (c *Container) Download(mxcURL string) (data []byte, fullID string, err err
err = ioutil.WriteFile(cacheFile, data, 0600)
return
}
-func (c *Container) getCachePath(homeserver, fileID string) string {
+
+func (c *Container) GetCachePath(homeserver, fileID string) string {
dir := filepath.Join(c.config.MediaDir, homeserver)
err := os.MkdirAll(dir, 0700)
diff --git a/ui/message-view.go b/ui/message-view.go
index 87dc993..5584d3e 100644
--- a/ui/message-view.go
+++ b/ui/message-view.go
@@ -22,6 +22,7 @@ import (
"math"
"os"
+ "maunium.net/go/gomuks/lib/open"
"maunium.net/go/gomuks/ui/messages/tstring"
"maunium.net/go/tcell"
"maunium.net/go/gomuks/debug"
@@ -88,7 +89,7 @@ func (view *MessageView) SaveHistory(path string) error {
return nil
}
-func (view *MessageView) LoadHistory(path string) (int, error) {
+func (view *MessageView) LoadHistory(gmx ifc.Gomuks, path string) (int, error) {
file, err := os.OpenFile(path, os.O_RDONLY, 0600)
if err != nil {
if os.IsNotExist(err) {
@@ -112,6 +113,7 @@ func (view *MessageView) LoadHistory(path string) (int, error) {
if message != nil {
view.messages[index-indexOffset] = message
view.updateWidestSender(message.Sender())
+ message.RegisterGomuks(gmx)
} else {
indexOffset++
}
@@ -251,6 +253,30 @@ func (view *MessageView) recalculateBuffers() {
}
}
+func (view *MessageView) HandleClick(x, y int, button tcell.ButtonMask) {
+ if button != tcell.Button1 {
+ return
+ }
+
+ _, _, _, height := view.GetRect()
+ line := view.TotalHeight() - view.ScrollOffset - height + y
+ if line < 0 || line >= view.TotalHeight() {
+ return
+ }
+
+ message := view.metaBuffer[line]
+ imageMessage, ok := message.(*messages.UIImageMessage)
+ if !ok {
+ uiMessage, ok := message.(messages.UIMessage)
+ if ok {
+ debug.Print("Message clicked:", uiMessage.Text())
+ }
+ return
+ }
+
+ open.Open(imageMessage.Path())
+}
+
const PaddingAtTop = 5
func (view *MessageView) AddScrollOffset(diff int) {
diff --git a/ui/messages/expandedtextmessage.go b/ui/messages/expandedtextmessage.go
new file mode 100644
index 0000000..1d6030a
--- /dev/null
+++ b/ui/messages/expandedtextmessage.go
@@ -0,0 +1,86 @@
+// gomuks - A terminal Matrix client written in Go.
+// Copyright (C) 2018 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package messages
+
+import (
+ "encoding/gob"
+ "time"
+
+ "maunium.net/go/gomuks/interface"
+ "maunium.net/go/gomuks/ui/messages/tstring"
+ "maunium.net/go/gomuks/ui/widget"
+)
+
+func init() {
+ gob.Register(&UITextMessage{})
+ gob.Register(&UIExpandedTextMessage{})
+}
+
+type UIExpandedTextMessage struct {
+ UITextMessage
+ MsgTStringText tstring.TString
+}
+
+// NewExpandedTextMessage creates a new UIExpandedTextMessage object with the provided values and the default state.
+func NewExpandedTextMessage(id, sender, msgtype string, text tstring.TString, timestamp time.Time) UIMessage {
+ return &UIExpandedTextMessage{
+ UITextMessage{
+ MsgSender: sender,
+ MsgTimestamp: timestamp,
+ MsgSenderColor: widget.GetHashColor(sender),
+ MsgType: msgtype,
+ MsgText: text.String(),
+ MsgID: id,
+ prevBufferWidth: 0,
+ MsgState: ifc.MessageStateDefault,
+ MsgIsHighlight: false,
+ MsgIsService: false,
+ },
+ text,
+ }
+}
+
+func (msg *UIExpandedTextMessage) GetTStringText() tstring.TString {
+ return msg.MsgTStringText
+}
+
+// CopyFrom replaces the content of this message object with the content of the given object.
+func (msg *UIExpandedTextMessage) CopyFrom(from ifc.MessageMeta) {
+ msg.MsgSender = from.Sender()
+ msg.MsgSenderColor = from.SenderColor()
+
+ fromMsg, ok := from.(UIMessage)
+ if ok {
+ msg.MsgSender = fromMsg.RealSender()
+ msg.MsgID = fromMsg.ID()
+ msg.MsgType = fromMsg.Type()
+ msg.MsgTimestamp = fromMsg.Timestamp()
+ msg.MsgState = fromMsg.State()
+ msg.MsgIsService = fromMsg.IsService()
+ msg.MsgIsHighlight = fromMsg.IsHighlight()
+ msg.buffer = nil
+
+ fromExpandedMsg, ok := from.(*UIExpandedTextMessage)
+ if ok {
+ msg.MsgTStringText = fromExpandedMsg.MsgTStringText
+ } else {
+ msg.MsgTStringText = tstring.NewColorTString(fromMsg.Text(), from.TextColor())
+ }
+
+ msg.RecalculateBuffer()
+ }
+}
diff --git a/ui/messages/imagemessage.go b/ui/messages/imagemessage.go
index 7129e5a..5282d44 100644
--- a/ui/messages/imagemessage.go
+++ b/ui/messages/imagemessage.go
@@ -19,15 +19,16 @@ package messages
import (
"bytes"
"encoding/gob"
+ "fmt"
"time"
"image/color"
"maunium.net/go/gomuks/debug"
"maunium.net/go/gomuks/interface"
+ "maunium.net/go/gomuks/lib/ansimage"
"maunium.net/go/gomuks/ui/messages/tstring"
"maunium.net/go/gomuks/ui/widget"
- "maunium.net/go/gomuks/lib/ansimage"
"maunium.net/go/tcell"
)
@@ -37,12 +38,15 @@ func init() {
type UIImageMessage struct {
UITextMessage
- Path string
- data []byte
+ Homeserver string
+ FileID string
+ data []byte
+
+ gmx ifc.Gomuks
}
// NewImageMessage creates a new UIImageMessage object with the provided values and the default state.
-func NewImageMessage(id, sender, msgtype string, path string, data []byte, timestamp time.Time) UIMessage {
+func NewImageMessage(gmx ifc.Gomuks, id, sender, msgtype, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
return &UIImageMessage{
UITextMessage{
MsgSender: sender,
@@ -55,11 +59,39 @@ func NewImageMessage(id, sender, msgtype string, path string, data []byte, times
MsgIsHighlight: false,
MsgIsService: false,
},
- path,
+ homeserver,
+ fileID,
data,
+ gmx,
+ }
+}
+
+func (msg *UIImageMessage) RegisterGomuks(gmx ifc.Gomuks) {
+ msg.gmx = gmx
+
+ debug.Print(len(msg.data), msg.data)
+ if len(msg.data) == 0 {
+ go func() {
+ defer gmx.Recover()
+ msg.updateData()
+ }()
}
}
+func (msg *UIImageMessage) updateData() {
+ debug.Print("Loading image:", msg.Homeserver, msg.FileID)
+ data, _, _, err := msg.gmx.Matrix().Download(fmt.Sprintf("mxc://%s/%s", msg.Homeserver, msg.FileID))
+ if err != nil {
+ debug.Print("Failed to download image %s/%s: %v", msg.Homeserver, msg.FileID, err)
+ return
+ }
+ msg.data = data
+}
+
+func (msg *UIImageMessage) Path() string {
+ return msg.gmx.Matrix().GetCachePath(msg.Homeserver, msg.FileID)
+}
+
// CopyFrom replaces the content of this message object with the content of the given object.
func (msg *UIImageMessage) CopyFrom(from ifc.MessageMeta) {
msg.MsgSender = from.Sender()
diff --git a/ui/messages/message.go b/ui/messages/message.go
index ac118ad..6ebfb6d 100644
--- a/ui/messages/message.go
+++ b/ui/messages/message.go
@@ -31,6 +31,7 @@ type UIMessage interface {
Height() int
RealSender() string
+ RegisterGomuks(gmx ifc.Gomuks)
}
const DateFormat = "January _2, 2006"
diff --git a/ui/messages/parser.go b/ui/messages/parser.go
index 22ba4e7..af76bf3 100644
--- a/ui/messages/parser.go
+++ b/ui/messages/parser.go
@@ -29,14 +29,14 @@ import (
"maunium.net/go/tcell"
)
-func ParseEvent(mx ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Event) UIMessage {
+func ParseEvent(gmx ifc.Gomuks, room *rooms.Room, evt *gomatrix.Event) UIMessage {
member := room.GetMember(evt.Sender)
if member != nil {
evt.Sender = member.DisplayName
}
switch evt.Type {
case "m.room.message":
- return ParseMessage(mx, evt)
+ return ParseMessage(gmx, evt)
case "m.room.member":
return ParseMembershipEvent(evt)
}
@@ -51,7 +51,7 @@ func unixToTime(unix int64) time.Time {
return timestamp
}
-func ParseMessage(mx ifc.MatrixContainer, evt *gomatrix.Event) UIMessage {
+func ParseMessage(gmx ifc.Gomuks, evt *gomatrix.Event) UIMessage {
msgtype, _ := evt.Content["msgtype"].(string)
ts := unixToTime(evt.Timestamp)
switch msgtype {
@@ -60,11 +60,11 @@ func ParseMessage(mx ifc.MatrixContainer, evt *gomatrix.Event) UIMessage {
return NewTextMessage(evt.ID, evt.Sender, msgtype, text, ts)
case "m.image":
url, _ := evt.Content["url"].(string)
- data, path, err := mx.Download(url)
+ data, hs, id, err := gmx.Matrix().Download(url)
if err != nil {
debug.Printf("Failed to download %s: %v", url, err)
}
- return NewImageMessage(evt.ID, evt.Sender, msgtype, path, data, ts)
+ return NewImageMessage(gmx, evt.ID, evt.Sender, msgtype, hs, id, data, ts)
}
return nil
}
diff --git a/ui/messages/textmessage.go b/ui/messages/textmessage.go
index 12b098d..4587d49 100644
--- a/ui/messages/textmessage.go
+++ b/ui/messages/textmessage.go
@@ -22,70 +22,14 @@ import (
"regexp"
"time"
- "maunium.net/go/gomuks/ui/messages/tstring"
- "maunium.net/go/tcell"
"maunium.net/go/gomuks/interface"
+ "maunium.net/go/gomuks/ui/messages/tstring"
"maunium.net/go/gomuks/ui/widget"
+ "maunium.net/go/tcell"
)
func init() {
gob.Register(&UITextMessage{})
- gob.Register(&UIExpandedTextMessage{})
-}
-
-type UIExpandedTextMessage struct {
- UITextMessage
- MsgTStringText tstring.TString
-}
-
-// NewExpandedTextMessage creates a new UIExpandedTextMessage object with the provided values and the default state.
-func NewExpandedTextMessage(id, sender, msgtype string, text tstring.TString, timestamp time.Time) UIMessage {
- return &UIExpandedTextMessage{
- UITextMessage{
- MsgSender: sender,
- MsgTimestamp: timestamp,
- MsgSenderColor: widget.GetHashColor(sender),
- MsgType: msgtype,
- MsgText: text.String(),
- MsgID: id,
- prevBufferWidth: 0,
- MsgState: ifc.MessageStateDefault,
- MsgIsHighlight: false,
- MsgIsService: false,
- },
- text,
- }
-}
-
-func (msg *UIExpandedTextMessage) GetTStringText() tstring.TString {
- return msg.MsgTStringText
-}
-
-// CopyFrom replaces the content of this message object with the content of the given object.
-func (msg *UIExpandedTextMessage) CopyFrom(from ifc.MessageMeta) {
- msg.MsgSender = from.Sender()
- msg.MsgSenderColor = from.SenderColor()
-
- fromMsg, ok := from.(UIMessage)
- if ok {
- msg.MsgSender = fromMsg.RealSender()
- msg.MsgID = fromMsg.ID()
- msg.MsgType = fromMsg.Type()
- msg.MsgTimestamp = fromMsg.Timestamp()
- msg.MsgState = fromMsg.State()
- msg.MsgIsService = fromMsg.IsService()
- msg.MsgIsHighlight = fromMsg.IsHighlight()
- msg.buffer = nil
-
- fromExpandedMsg, ok := from.(*UIExpandedTextMessage)
- if ok {
- msg.MsgTStringText = fromExpandedMsg.MsgTStringText
- } else {
- msg.MsgTStringText = tstring.NewColorTString(fromMsg.Text(), from.TextColor())
- }
-
- msg.RecalculateBuffer()
- }
}
type UITextMessage struct {
@@ -118,6 +62,8 @@ func NewTextMessage(id, sender, msgtype, text string, timestamp time.Time) UIMes
}
}
+func (msg *UITextMessage) RegisterGomuks(gmx ifc.Gomuks) {}
+
// CopyFrom replaces the content of this message object with the content of the given object.
func (msg *UITextMessage) CopyFrom(from ifc.MessageMeta) {
msg.MsgSender = from.Sender()
diff --git a/ui/room-view.go b/ui/room-view.go
index b7c9a34..ba3b004 100644
--- a/ui/room-view.go
+++ b/ui/room-view.go
@@ -81,8 +81,8 @@ func (view *RoomView) SaveHistory(dir string) error {
return view.MessageView().SaveHistory(view.logPath(dir))
}
-func (view *RoomView) LoadHistory(dir string) (int, error) {
- return view.MessageView().LoadHistory(view.logPath(dir))
+func (view *RoomView) LoadHistory(gmx ifc.Gomuks, dir string) (int, error) {
+ return view.MessageView().LoadHistory(gmx, view.logPath(dir))
}
func (view *RoomView) SetTabCompleteFunc(fn func(room *RoomView, text string, cursorOffset int) string) *RoomView {
diff --git a/ui/view-main.go b/ui/view-main.go
index 056f8a0..b21b3f4 100644
--- a/ui/view-main.go
+++ b/ui/view-main.go
@@ -23,7 +23,6 @@ import (
"time"
"unicode"
- "maunium.net/go/tcell"
"github.com/mattn/go-runewidth"
"maunium.net/go/gomatrix"
"maunium.net/go/gomuks/config"
@@ -34,6 +33,7 @@ import (
"maunium.net/go/gomuks/matrix/rooms"
"maunium.net/go/gomuks/ui/messages"
"maunium.net/go/gomuks/ui/widget"
+ "maunium.net/go/tcell"
"maunium.net/go/tview"
)
@@ -221,7 +221,7 @@ func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *
const WheelScrollOffsetDiff = 3
func (view *MainView) MouseEventHandler(roomView *RoomView, event *tcell.EventMouse) *tcell.EventMouse {
- if event.Buttons() == tcell.ButtonNone {
+ if event.Buttons() == tcell.ButtonNone || event.HasMotion() {
return event
}
view.BumpFocus()
@@ -230,11 +230,6 @@ func (view *MainView) MouseEventHandler(roomView *RoomView, event *tcell.EventMo
x, y := event.Position()
switch event.Buttons() {
- case tcell.Button1:
- mx, my, mw, mh := msgView.GetRect()
- if x >= mx && y >= my && x < mx+mw && y < my+mh {
- debug.Print("Message view clicked")
- }
case tcell.WheelUp:
if msgView.IsAtTop() {
go view.LoadHistory(roomView.Room.ID, false)
@@ -252,7 +247,12 @@ func (view *MainView) MouseEventHandler(roomView *RoomView, event *tcell.EventMo
roomView.Room.MarkRead()
}
default:
- debug.Print("Mouse event received:", event.Buttons(), event.Modifiers(), x, y)
+ mx, my, mw, mh := msgView.GetRect()
+ if x >= mx && y >= my && x < mx+mw && y < my+mh {
+ msgView.HandleClick(x-mx, y-my, event.Buttons())
+ } else {
+ debug.Print("Mouse event received:", event.Buttons(), event.Modifiers(), x, y)
+ }
return event
}
@@ -315,7 +315,7 @@ func (view *MainView) addRoom(index int, room string) {
view.roomView.AddPage(room, roomView, true, false)
roomView.UpdateUserList()
- count, err := roomView.LoadHistory(view.config.HistoryDir)
+ count, err := roomView.LoadHistory(view.gmx, view.config.HistoryDir)
if err != nil {
debug.Printf("Failed to load history of %s: %v", roomView.Room.GetTitle(), err)
} else if count <= 0 {
@@ -466,5 +466,5 @@ func (view *MainView) LoadHistory(room string, initial bool) {
}
func (view *MainView) ParseEvent(roomView ifc.RoomView, evt *gomatrix.Event) ifc.Message {
- return messages.ParseEvent(view.matrix, roomView.MxRoom(), evt)
+ return messages.ParseEvent(view.gmx, roomView.MxRoom(), evt)
}