Add bare mode and fix terminal resize bug. Fixes #48
This commit is contained in:
		@@ -50,6 +50,7 @@ type MessageView struct {
 | 
			
		||||
	prevWidth    int
 | 
			
		||||
	prevHeight   int
 | 
			
		||||
	prevMsgCount int
 | 
			
		||||
	prevBareMode bool
 | 
			
		||||
 | 
			
		||||
	messageIDs map[string]messages.UIMessage
 | 
			
		||||
	messages   []messages.UIMessage
 | 
			
		||||
@@ -76,6 +77,7 @@ func NewMessageView(parent *RoomView) *MessageView {
 | 
			
		||||
		prevWidth:    -1,
 | 
			
		||||
		prevHeight:   -1,
 | 
			
		||||
		prevMsgCount: -1,
 | 
			
		||||
		prevBareMode: false,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -168,9 +170,12 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction ifc.Messag
 | 
			
		||||
 | 
			
		||||
	view.updateWidestSender(message.Sender())
 | 
			
		||||
 | 
			
		||||
	_, _, width, _ := view.GetInnerRect()
 | 
			
		||||
	width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
 | 
			
		||||
	message.CalculateBuffer(width)
 | 
			
		||||
	_, _, width, _ := view.GetRect()
 | 
			
		||||
	bare := view.parent.parent.bareDisplay
 | 
			
		||||
	if !bare {
 | 
			
		||||
		width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
 | 
			
		||||
	}
 | 
			
		||||
	message.CalculateBuffer(bare, width)
 | 
			
		||||
 | 
			
		||||
	if direction == ifc.AppendMessage {
 | 
			
		||||
		if view.ScrollOffset > 0 {
 | 
			
		||||
@@ -258,11 +263,13 @@ func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) recalculateBuffers() {
 | 
			
		||||
	_, _, width, height := view.GetInnerRect()
 | 
			
		||||
 | 
			
		||||
	width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
 | 
			
		||||
	recalculateMessageBuffers := width != view.prevWidth
 | 
			
		||||
	if height != view.prevHeight || recalculateMessageBuffers || len(view.messages) != view.prevMsgCount {
 | 
			
		||||
	_, _, width, height := view.GetRect()
 | 
			
		||||
	bareMode := view.parent.parent.bareDisplay
 | 
			
		||||
	if !bareMode {
 | 
			
		||||
		width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
 | 
			
		||||
	}
 | 
			
		||||
	recalculateMessageBuffers := width != view.prevWidth || bareMode != view.prevBareMode
 | 
			
		||||
	if recalculateMessageBuffers || len(view.messages) != view.prevMsgCount {
 | 
			
		||||
		view.textBuffer = []tstring.TString{}
 | 
			
		||||
		view.metaBuffer = []ifc.MessageMeta{}
 | 
			
		||||
		view.prevMsgCount = 0
 | 
			
		||||
@@ -272,13 +279,14 @@ func (view *MessageView) recalculateBuffers() {
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			if recalculateMessageBuffers {
 | 
			
		||||
				message.CalculateBuffer(width)
 | 
			
		||||
				message.CalculateBuffer(bareMode, width)
 | 
			
		||||
			}
 | 
			
		||||
			view.appendBuffer(message)
 | 
			
		||||
		}
 | 
			
		||||
		view.prevHeight = height
 | 
			
		||||
		view.prevWidth = width
 | 
			
		||||
	}
 | 
			
		||||
	view.prevHeight = height
 | 
			
		||||
	view.prevWidth = width
 | 
			
		||||
	view.prevBareMode = bareMode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) handleMessageClick(message ifc.MessageMeta) bool {
 | 
			
		||||
@@ -362,7 +370,7 @@ func (view *MessageView) HandleClick(x, y int, button tcell.ButtonMask) bool {
 | 
			
		||||
const PaddingAtTop = 5
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) AddScrollOffset(diff int) {
 | 
			
		||||
	_, _, _, height := view.GetInnerRect()
 | 
			
		||||
	_, _, _, height := view.GetRect()
 | 
			
		||||
 | 
			
		||||
	totalHeight := view.TotalHeight()
 | 
			
		||||
	if diff >= 0 && view.ScrollOffset+diff >= totalHeight-height+PaddingAtTop {
 | 
			
		||||
@@ -380,7 +388,7 @@ func (view *MessageView) AddScrollOffset(diff int) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) Height() int {
 | 
			
		||||
	_, _, _, height := view.GetInnerRect()
 | 
			
		||||
	_, _, _, height := view.GetRect()
 | 
			
		||||
	return height
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -389,7 +397,7 @@ func (view *MessageView) TotalHeight() int {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) IsAtTop() bool {
 | 
			
		||||
	_, _, _, height := view.GetInnerRect()
 | 
			
		||||
	_, _, _, height := view.GetRect()
 | 
			
		||||
	totalHeight := len(view.textBuffer)
 | 
			
		||||
	return view.ScrollOffset >= totalHeight-height+PaddingAtTop
 | 
			
		||||
}
 | 
			
		||||
@@ -442,14 +450,14 @@ func (view *MessageView) getIndexOffset(screen tcell.Screen, height, messageX in
 | 
			
		||||
		if view.LoadingMessages {
 | 
			
		||||
			message = "Loading more messages..."
 | 
			
		||||
		}
 | 
			
		||||
		_, y, _, _ := view.GetInnerRect()
 | 
			
		||||
		_, y, _, _ := view.GetRect()
 | 
			
		||||
		widget.WriteLineSimpleColor(screen, message, messageX, y, tcell.ColorGreen)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) Draw(screen tcell.Screen) {
 | 
			
		||||
	x, y, _, height := view.GetInnerRect()
 | 
			
		||||
	x, y, _, height := view.GetRect()
 | 
			
		||||
	view.recalculateBuffers()
 | 
			
		||||
 | 
			
		||||
	if view.TotalHeight() == 0 {
 | 
			
		||||
@@ -461,6 +469,11 @@ func (view *MessageView) Draw(screen tcell.Screen) {
 | 
			
		||||
	messageX := usernameX + view.widestSender + SenderMessageGap
 | 
			
		||||
	separatorX := usernameX + view.widestSender + SenderSeparatorGap
 | 
			
		||||
 | 
			
		||||
	bareMode := view.parent.parent.bareDisplay
 | 
			
		||||
	if bareMode {
 | 
			
		||||
		messageX = 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	indexOffset := view.getIndexOffset(screen, height, messageX)
 | 
			
		||||
 | 
			
		||||
	if len(view.textBuffer) != len(view.metaBuffer) {
 | 
			
		||||
@@ -491,14 +504,16 @@ func (view *MessageView) Draw(screen tcell.Screen) {
 | 
			
		||||
 | 
			
		||||
		firstLine = false
 | 
			
		||||
 | 
			
		||||
		screen.SetContent(separatorX, y+line, borderChar, nil, borderStyle)
 | 
			
		||||
		if !bareMode {
 | 
			
		||||
			screen.SetContent(separatorX, y+line, borderChar, nil, borderStyle)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		text, meta := view.textBuffer[index], view.metaBuffer[index]
 | 
			
		||||
		if meta != prevMeta {
 | 
			
		||||
			if len(meta.FormatTime()) > 0 {
 | 
			
		||||
				widget.WriteLineSimpleColor(screen, meta.FormatTime(), x, y+line, meta.TimestampColor())
 | 
			
		||||
			}
 | 
			
		||||
			if prevMeta == nil || meta.Sender() != prevMeta.Sender() {
 | 
			
		||||
			if !bareMode && (prevMeta == nil || meta.Sender() != prevMeta.Sender()) {
 | 
			
		||||
				widget.WriteLineColor(
 | 
			
		||||
					screen, tview.AlignRight, meta.Sender(),
 | 
			
		||||
					usernameX, y+line, view.widestSender,
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,9 @@ type BaseMessage struct {
 | 
			
		||||
	MsgIsHighlight  bool
 | 
			
		||||
	MsgIsService    bool
 | 
			
		||||
	buffer          []tstring.TString
 | 
			
		||||
	plainBuffer     []tstring.TString
 | 
			
		||||
	prevBufferWidth int
 | 
			
		||||
	prevBareMode    bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newBaseMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseMessage {
 | 
			
		||||
@@ -53,6 +55,7 @@ func newBaseMessage(id, sender, displayname, msgtype string, timestamp time.Time
 | 
			
		||||
		MsgType:         msgtype,
 | 
			
		||||
		MsgID:           id,
 | 
			
		||||
		prevBufferWidth: 0,
 | 
			
		||||
		prevBareMode:    false,
 | 
			
		||||
		MsgState:        ifc.MessageStateDefault,
 | 
			
		||||
		MsgIsHighlight:  false,
 | 
			
		||||
		MsgIsService:    false,
 | 
			
		||||
 
 | 
			
		||||
@@ -28,14 +28,14 @@ func init() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ExpandedTextMessage struct {
 | 
			
		||||
	BaseTextMessage
 | 
			
		||||
	BaseMessage
 | 
			
		||||
	MsgText tstring.TString
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewExpandedTextMessage creates a new ExpandedTextMessage object with the provided values and the default state.
 | 
			
		||||
func NewExpandedTextMessage(id, sender, displayname, msgtype string, text tstring.TString, timestamp time.Time) UIMessage {
 | 
			
		||||
	return &ExpandedTextMessage{
 | 
			
		||||
		BaseTextMessage: newBaseTextMessage(id, sender, displayname, msgtype, timestamp),
 | 
			
		||||
		BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
 | 
			
		||||
		MsgText:         text,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -48,11 +48,15 @@ func (msg *ExpandedTextMessage) NotificationContent() string {
 | 
			
		||||
	return msg.MsgText.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (msg *ExpandedTextMessage) CalculateBuffer(width int) {
 | 
			
		||||
	msg.BaseTextMessage.calculateBufferWithText(msg.MsgText, width)
 | 
			
		||||
func (msg *ExpandedTextMessage) PlainText() string {
 | 
			
		||||
	return msg.MsgText.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (msg *ExpandedTextMessage) CalculateBuffer(bare bool, width int) {
 | 
			
		||||
	msg.calculateBufferWithText(bare, msg.MsgText, width)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RecalculateBuffer calculates the buffer again with the previously provided width.
 | 
			
		||||
func (msg *ExpandedTextMessage) RecalculateBuffer() {
 | 
			
		||||
	msg.CalculateBuffer(msg.prevBufferWidth)
 | 
			
		||||
	msg.CalculateBuffer(msg.prevBareMode, msg.prevBufferWidth)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,7 @@ func init() {
 | 
			
		||||
 | 
			
		||||
type ImageMessage struct {
 | 
			
		||||
	BaseMessage
 | 
			
		||||
	Body string
 | 
			
		||||
	Homeserver string
 | 
			
		||||
	FileID     string
 | 
			
		||||
	data       []byte
 | 
			
		||||
@@ -45,9 +46,10 @@ type ImageMessage struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewImageMessage creates a new ImageMessage object with the provided values and the default state.
 | 
			
		||||
func NewImageMessage(matrix ifc.MatrixContainer, id, sender, displayname, msgtype, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
 | 
			
		||||
func NewImageMessage(matrix ifc.MatrixContainer, id, sender, displayname, msgtype, body, homeserver, fileID string, data []byte, timestamp time.Time) UIMessage {
 | 
			
		||||
	return &ImageMessage{
 | 
			
		||||
		newBaseMessage(id, sender, displayname, msgtype, timestamp),
 | 
			
		||||
		body,
 | 
			
		||||
		homeserver,
 | 
			
		||||
		fileID,
 | 
			
		||||
		data,
 | 
			
		||||
@@ -67,6 +69,10 @@ func (msg *ImageMessage) NotificationContent() string {
 | 
			
		||||
	return "Sent an image"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (msg *ImageMessage) PlainText() string {
 | 
			
		||||
	return fmt.Sprintf("%s: %s", msg.Body, msg.matrix.GetDownloadURL(msg.Homeserver, msg.FileID))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (msg *ImageMessage) updateData() {
 | 
			
		||||
	defer debug.Recover()
 | 
			
		||||
	debug.Print("Loading image:", msg.Homeserver, msg.FileID)
 | 
			
		||||
@@ -86,11 +92,16 @@ func (msg *ImageMessage) Path() string {
 | 
			
		||||
// CalculateBuffer generates the internal buffer for this message that consists
 | 
			
		||||
// of the text of this message split into lines at most as wide as the width
 | 
			
		||||
// parameter.
 | 
			
		||||
func (msg *ImageMessage) CalculateBuffer(width int) {
 | 
			
		||||
func (msg *ImageMessage) CalculateBuffer(bare bool, width int) {
 | 
			
		||||
	if width < 2 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if bare {
 | 
			
		||||
		msg.calculateBufferWithText(bare, tstring.NewTString(msg.PlainText()), width)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	image, err := ansimage.NewScaledFromReader(bytes.NewReader(msg.data), 0, width, color.Black)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		msg.buffer = []tstring.TString{tstring.NewColorTString("Failed to display image", tcell.ColorRed)}
 | 
			
		||||
@@ -100,9 +111,10 @@ func (msg *ImageMessage) CalculateBuffer(width int) {
 | 
			
		||||
 | 
			
		||||
	msg.buffer = image.Render()
 | 
			
		||||
	msg.prevBufferWidth = width
 | 
			
		||||
	msg.prevBareMode = false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RecalculateBuffer calculates the buffer again with the previously provided width.
 | 
			
		||||
func (msg *ImageMessage) RecalculateBuffer() {
 | 
			
		||||
	msg.CalculateBuffer(msg.prevBufferWidth)
 | 
			
		||||
	msg.CalculateBuffer(msg.prevBareMode, msg.prevBufferWidth)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ import (
 | 
			
		||||
type UIMessage interface {
 | 
			
		||||
	ifc.Message
 | 
			
		||||
 | 
			
		||||
	CalculateBuffer(width int)
 | 
			
		||||
	CalculateBuffer(bare bool, width int)
 | 
			
		||||
	RecalculateBuffer()
 | 
			
		||||
	Buffer() []tstring.TString
 | 
			
		||||
	Height() int
 | 
			
		||||
 
 | 
			
		||||
@@ -56,6 +56,7 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Ev
 | 
			
		||||
		displayname = member.DisplayName
 | 
			
		||||
	}
 | 
			
		||||
	msgtype, _ := evt.Content["msgtype"].(string)
 | 
			
		||||
	text, _ := evt.Content["body"].(string)
 | 
			
		||||
	ts := unixToTime(evt.Timestamp)
 | 
			
		||||
	switch msgtype {
 | 
			
		||||
	case "m.text", "m.notice", "m.emote":
 | 
			
		||||
@@ -64,7 +65,6 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Ev
 | 
			
		||||
			text := ParseHTMLMessage(room, evt, displayname)
 | 
			
		||||
			return messages.NewExpandedTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
 | 
			
		||||
		}
 | 
			
		||||
		text, _ := evt.Content["body"].(string)
 | 
			
		||||
		text = strings.Replace(text, "\t", "    ", -1)
 | 
			
		||||
		return messages.NewTextMessage(evt.ID, evt.Sender, displayname, msgtype, text, ts)
 | 
			
		||||
	case "m.image":
 | 
			
		||||
@@ -73,7 +73,7 @@ func ParseMessage(matrix ifc.MatrixContainer, room *rooms.Room, evt *gomatrix.Ev
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			debug.Printf("Failed to download %s: %v", url, err)
 | 
			
		||||
		}
 | 
			
		||||
		return messages.NewImageMessage(matrix, evt.ID, evt.Sender, displayname, msgtype, hs, id, data, ts)
 | 
			
		||||
		return messages.NewImageMessage(matrix, evt.ID, evt.Sender, displayname, msgtype, text, hs, id, data, ts)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,35 +17,26 @@
 | 
			
		||||
package messages
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/gob"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"maunium.net/go/gomuks/ui/messages/tstring"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	gob.Register(BaseTextMessage{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type BaseTextMessage struct {
 | 
			
		||||
	BaseMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newBaseTextMessage(id, sender, displayname, msgtype string, timestamp time.Time) BaseTextMessage {
 | 
			
		||||
	return BaseTextMessage{newBaseMessage(id, sender, displayname, msgtype, timestamp)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Regular expressions used to split lines when calculating the buffer.
 | 
			
		||||
//
 | 
			
		||||
// From tview/textview.go
 | 
			
		||||
var (
 | 
			
		||||
	boundaryPattern = regexp.MustCompile("([[:punct:]]\\s*|\\s+)")
 | 
			
		||||
	boundaryPattern = regexp.MustCompile(`([[:punct:]]\s*|\s+)`)
 | 
			
		||||
	bareBoundaryPattern = regexp.MustCompile(`(\s+)`)
 | 
			
		||||
	spacePattern    = regexp.MustCompile(`\s+`)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func matchBoundaryPattern(extract tstring.TString) tstring.TString {
 | 
			
		||||
	matches := boundaryPattern.FindAllStringIndex(extract.String(), -1)
 | 
			
		||||
func matchBoundaryPattern(bare bool, extract tstring.TString) tstring.TString {
 | 
			
		||||
	regex := boundaryPattern
 | 
			
		||||
	if bare {
 | 
			
		||||
		regex = bareBoundaryPattern
 | 
			
		||||
	}
 | 
			
		||||
	matches := regex.FindAllStringIndex(extract.String(), -1)
 | 
			
		||||
	if len(matches) > 0 {
 | 
			
		||||
		if match := matches[len(matches)-1]; len(match) >= 2 {
 | 
			
		||||
			if until := match[1]; until < len(extract) {
 | 
			
		||||
@@ -59,13 +50,20 @@ func matchBoundaryPattern(extract tstring.TString) tstring.TString {
 | 
			
		||||
// CalculateBuffer generates the internal buffer for this message that consists
 | 
			
		||||
// of the text of this message split into lines at most as wide as the width
 | 
			
		||||
// parameter.
 | 
			
		||||
func (msg *BaseTextMessage) calculateBufferWithText(text tstring.TString, width int) {
 | 
			
		||||
func (msg *BaseMessage) calculateBufferWithText(bare bool, text tstring.TString, width int) {
 | 
			
		||||
	if width < 2 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	msg.buffer = []tstring.TString{}
 | 
			
		||||
 | 
			
		||||
	if bare {
 | 
			
		||||
		text = tstring.
 | 
			
		||||
			NewTString(msg.FormatTime()).
 | 
			
		||||
			AppendTString(tstring.NewColorTString(fmt.Sprintf(" <%s> ", msg.Sender()), msg.SenderColor())).
 | 
			
		||||
			AppendTString(text)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	forcedLinebreaks := text.Split('\n')
 | 
			
		||||
	newlines := 0
 | 
			
		||||
	for _, str := range forcedLinebreaks {
 | 
			
		||||
@@ -82,11 +80,12 @@ func (msg *BaseTextMessage) calculateBufferWithText(text tstring.TString, width
 | 
			
		||||
				if spaces := spacePattern.FindStringIndex(str[len(extract):].String()); spaces != nil && spaces[0] == 0 {
 | 
			
		||||
					extract = str[:len(extract)+spaces[1]]
 | 
			
		||||
				}
 | 
			
		||||
				extract = matchBoundaryPattern(extract)
 | 
			
		||||
				extract = matchBoundaryPattern(bare, extract)
 | 
			
		||||
			}
 | 
			
		||||
			msg.buffer = append(msg.buffer, extract)
 | 
			
		||||
			str = str[len(extract):]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	msg.prevBufferWidth = width
 | 
			
		||||
	msg.prevBareMode = bare
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ func init() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TextMessage struct {
 | 
			
		||||
	BaseTextMessage
 | 
			
		||||
	BaseMessage
 | 
			
		||||
	cache   tstring.TString
 | 
			
		||||
	MsgText string
 | 
			
		||||
}
 | 
			
		||||
@@ -38,7 +38,7 @@ type TextMessage struct {
 | 
			
		||||
// NewTextMessage creates a new UITextMessage object with the provided values and the default state.
 | 
			
		||||
func NewTextMessage(id, sender, displayname, msgtype, text string, timestamp time.Time) UIMessage {
 | 
			
		||||
	return &TextMessage{
 | 
			
		||||
		BaseTextMessage: newBaseTextMessage(id, sender, displayname, msgtype, timestamp),
 | 
			
		||||
		BaseMessage: newBaseMessage(id, sender, displayname, msgtype, timestamp),
 | 
			
		||||
		MsgText:         text,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -57,22 +57,22 @@ func (msg *TextMessage) getCache() tstring.TString {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (msg *TextMessage) SetType(msgtype string) {
 | 
			
		||||
	msg.BaseTextMessage.SetType(msgtype)
 | 
			
		||||
	msg.BaseMessage.SetType(msgtype)
 | 
			
		||||
	msg.cache = nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (msg *TextMessage) SetState(state ifc.MessageState) {
 | 
			
		||||
	msg.BaseTextMessage.SetState(state)
 | 
			
		||||
	msg.BaseMessage.SetState(state)
 | 
			
		||||
	msg.cache = nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (msg *TextMessage) SetIsHighlight(isHighlight bool) {
 | 
			
		||||
	msg.BaseTextMessage.SetIsHighlight(isHighlight)
 | 
			
		||||
	msg.BaseMessage.SetIsHighlight(isHighlight)
 | 
			
		||||
	msg.cache = nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (msg *TextMessage) SetIsService(isService bool) {
 | 
			
		||||
	msg.BaseTextMessage.SetIsService(isService)
 | 
			
		||||
	msg.BaseMessage.SetIsService(isService)
 | 
			
		||||
	msg.cache = nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -80,11 +80,15 @@ func (msg *TextMessage) NotificationContent() string {
 | 
			
		||||
	return msg.MsgText
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (msg *TextMessage) CalculateBuffer(width int) {
 | 
			
		||||
	msg.BaseTextMessage.calculateBufferWithText(msg.getCache(), width)
 | 
			
		||||
func (msg *TextMessage) PlainText() string {
 | 
			
		||||
	return msg.MsgText
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (msg *TextMessage) CalculateBuffer(bare bool, width int) {
 | 
			
		||||
	msg.calculateBufferWithText(bare, msg.getCache(), width)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RecalculateBuffer calculates the buffer again with the previously provided width.
 | 
			
		||||
func (msg *TextMessage) RecalculateBuffer() {
 | 
			
		||||
	msg.CalculateBuffer(msg.prevBufferWidth)
 | 
			
		||||
	msg.CalculateBuffer(msg.prevBareMode, msg.prevBufferWidth)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -426,7 +426,7 @@ func (list *RoomList) GetTagDisplayName(tag string) string {
 | 
			
		||||
func (list *RoomList) Draw(screen tcell.Screen) {
 | 
			
		||||
	list.Box.Draw(screen)
 | 
			
		||||
 | 
			
		||||
	x, y, width, height := list.GetInnerRect()
 | 
			
		||||
	x, y, width, height := list.GetRect()
 | 
			
		||||
	yLimit := y + height
 | 
			
		||||
	y -= list.scrollOffset
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -147,23 +147,11 @@ func (view *RoomView) Focus(delegate func(p tview.Primitive)) {
 | 
			
		||||
	delegate(view.input)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Constants defining the size of the room view grid.
 | 
			
		||||
const (
 | 
			
		||||
	UserListBorderWidth   = 1
 | 
			
		||||
	UserListWidth         = 20
 | 
			
		||||
	StaticHorizontalSpace = UserListBorderWidth + UserListWidth
 | 
			
		||||
 | 
			
		||||
	TopicBarHeight      = 1
 | 
			
		||||
	StatusBarHeight     = 1
 | 
			
		||||
	InputBarHeight      = 1
 | 
			
		||||
	StaticVerticalSpace = TopicBarHeight + StatusBarHeight + InputBarHeight
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (view *RoomView) GetStatus() string {
 | 
			
		||||
	var buf strings.Builder
 | 
			
		||||
 | 
			
		||||
	if len(view.completions.list) > 0 {
 | 
			
		||||
		if view.completions.textCache != view.input.GetText() || view.completions.time.Add(10*time.Second).Before(time.Now()) {
 | 
			
		||||
		if view.completions.textCache != view.input.GetText() || view.completions.time.Add(10 * time.Second).Before(time.Now()) {
 | 
			
		||||
			view.completions.list = []string{}
 | 
			
		||||
		} else {
 | 
			
		||||
			buf.WriteString(strings.Join(view.completions.list, ", "))
 | 
			
		||||
@@ -184,11 +172,23 @@ func (view *RoomView) GetStatus() string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *RoomView) Draw(screen tcell.Screen) {
 | 
			
		||||
	x, y, width, height := view.GetInnerRect()
 | 
			
		||||
	x, y, width, height := view.GetRect()
 | 
			
		||||
	if width <= 0 || height <= 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Constants defining the size of the room view grid.
 | 
			
		||||
	const (
 | 
			
		||||
		UserListBorderWidth   = 1
 | 
			
		||||
		UserListWidth         = 20
 | 
			
		||||
		StaticHorizontalSpace = UserListBorderWidth + UserListWidth
 | 
			
		||||
 | 
			
		||||
		TopicBarHeight      = 1
 | 
			
		||||
		StatusBarHeight     = 1
 | 
			
		||||
		InputBarHeight      = 1
 | 
			
		||||
		StaticVerticalSpace = TopicBarHeight + StatusBarHeight + InputBarHeight
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// Calculate actual grid based on view rectangle and constants defined above.
 | 
			
		||||
	var (
 | 
			
		||||
		contentHeight = height - StaticVerticalSpace
 | 
			
		||||
@@ -202,12 +202,15 @@ func (view *RoomView) Draw(screen tcell.Screen) {
 | 
			
		||||
		statusRow  = contentRow + contentHeight
 | 
			
		||||
		inputRow   = statusRow + StatusBarHeight
 | 
			
		||||
	)
 | 
			
		||||
	if !view.parent.ShowUserList() {
 | 
			
		||||
		contentWidth = width
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Update the rectangles of all the children.
 | 
			
		||||
	view.topic.SetRect(x, topicRow, width, TopicBarHeight)
 | 
			
		||||
	view.content.SetRect(x, contentRow, contentWidth, contentHeight)
 | 
			
		||||
	view.status.SetRect(x, statusRow, width, StatusBarHeight)
 | 
			
		||||
	if userListColumn > x {
 | 
			
		||||
	if view.parent.ShowUserList() && userListColumn > x {
 | 
			
		||||
		view.userList.SetRect(userListColumn, contentRow, UserListWidth, contentHeight)
 | 
			
		||||
		view.ulBorder.SetRect(userListBorderColumn, contentRow, UserListBorderWidth, contentHeight)
 | 
			
		||||
	}
 | 
			
		||||
@@ -220,8 +223,10 @@ func (view *RoomView) Draw(screen tcell.Screen) {
 | 
			
		||||
	view.status.SetText(view.GetStatus())
 | 
			
		||||
	view.status.Draw(screen)
 | 
			
		||||
	view.input.Draw(screen)
 | 
			
		||||
	view.ulBorder.Draw(screen)
 | 
			
		||||
	view.userList.Draw(screen)
 | 
			
		||||
	if view.parent.ShowUserList() {
 | 
			
		||||
		view.ulBorder.Draw(screen)
 | 
			
		||||
		view.userList.Draw(screen)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *RoomView) SetCompletions(completions []string) {
 | 
			
		||||
 
 | 
			
		||||
@@ -48,6 +48,18 @@ type MainView struct {
 | 
			
		||||
	gmx    ifc.Gomuks
 | 
			
		||||
	config *config.Config
 | 
			
		||||
	parent *GomuksUI
 | 
			
		||||
 | 
			
		||||
	hideUserList bool
 | 
			
		||||
	hideRoomList bool
 | 
			
		||||
	bareDisplay  bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) ShowRoomList() bool {
 | 
			
		||||
	return !view.bareDisplay && !view.hideRoomList
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) ShowUserList() bool {
 | 
			
		||||
	return !view.bareDisplay && !view.hideUserList
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ui *GomuksUI) NewMainView() tview.Primitive {
 | 
			
		||||
@@ -63,10 +75,11 @@ func (ui *GomuksUI) NewMainView() tview.Primitive {
 | 
			
		||||
		parent: ui,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mainView.SetDirection(tview.FlexColumn)
 | 
			
		||||
	mainView.AddItem(mainView.roomList, 25, 0, false)
 | 
			
		||||
	mainView.AddItem(widget.NewBorder(), 1, 0, false)
 | 
			
		||||
	mainView.AddItem(mainView.roomView, 0, 1, true)
 | 
			
		||||
	mainView.
 | 
			
		||||
		SetDirection(tview.FlexColumn).
 | 
			
		||||
		AddItem(mainView.roomList, 25, 0, false).
 | 
			
		||||
		AddItem(widget.NewBorder(), 1, 0, false).
 | 
			
		||||
		AddItem(mainView.roomView, 0, 1, true)
 | 
			
		||||
	mainView.BumpFocus(nil)
 | 
			
		||||
 | 
			
		||||
	ui.mainView = mainView
 | 
			
		||||
@@ -74,6 +87,15 @@ func (ui *GomuksUI) NewMainView() tview.Primitive {
 | 
			
		||||
	return mainView
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) Draw(screen tcell.Screen) {
 | 
			
		||||
	if !view.ShowRoomList() {
 | 
			
		||||
		view.roomView.SetRect(view.GetRect())
 | 
			
		||||
		view.roomView.Draw(screen)
 | 
			
		||||
	} else {
 | 
			
		||||
		view.Flex.Draw(screen)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) BumpFocus(roomView *RoomView) {
 | 
			
		||||
	view.lastFocusTime = time.Now()
 | 
			
		||||
	view.MarkRead(roomView)
 | 
			
		||||
@@ -195,16 +217,20 @@ func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *
 | 
			
		||||
	view.BumpFocus(roomView)
 | 
			
		||||
 | 
			
		||||
	k := key.Key()
 | 
			
		||||
	c := key.Rune()
 | 
			
		||||
	if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt {
 | 
			
		||||
		switch k {
 | 
			
		||||
		case tcell.KeyDown:
 | 
			
		||||
		switch {
 | 
			
		||||
		case k == tcell.KeyDown:
 | 
			
		||||
			view.SwitchRoom(view.roomList.Next())
 | 
			
		||||
		case tcell.KeyUp:
 | 
			
		||||
		case k == tcell.KeyUp:
 | 
			
		||||
			view.SwitchRoom(view.roomList.Previous())
 | 
			
		||||
		case tcell.KeyEnter:
 | 
			
		||||
		case k == tcell.KeyEnter:
 | 
			
		||||
			searchModal := NewFuzzySearchModal(view, 42, 12)
 | 
			
		||||
			view.parent.views.AddPage("fuzzy-search-modal", searchModal, true, true)
 | 
			
		||||
			view.parent.app.SetFocus(searchModal)
 | 
			
		||||
		case c == 'l':
 | 
			
		||||
			view.bareDisplay = !view.bareDisplay
 | 
			
		||||
			view.parent.Render()
 | 
			
		||||
		default:
 | 
			
		||||
			return key
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user