Add locks and other sync stuff
This commit is contained in:
		@@ -20,6 +20,8 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
 | 
			
		||||
	"github.com/mattn/go-runewidth"
 | 
			
		||||
 | 
			
		||||
@@ -43,20 +45,24 @@ type MessageView struct {
 | 
			
		||||
	DateFormat      string
 | 
			
		||||
	TimestampFormat string
 | 
			
		||||
	TimestampWidth  int
 | 
			
		||||
	LoadingMessages bool
 | 
			
		||||
 | 
			
		||||
	widestSender int
 | 
			
		||||
	width        int
 | 
			
		||||
	height       int
 | 
			
		||||
	prevWidth    int
 | 
			
		||||
	prevHeight   int
 | 
			
		||||
	prevMsgCount int
 | 
			
		||||
	prevPrefs    config.UserPreferences
 | 
			
		||||
	// Used for locking
 | 
			
		||||
	loadingMessages int32
 | 
			
		||||
 | 
			
		||||
	messageIDs map[string]messages.UIMessage
 | 
			
		||||
	messages   []messages.UIMessage
 | 
			
		||||
	_widestSender uint32
 | 
			
		||||
	_width        uint32
 | 
			
		||||
	_height       uint32
 | 
			
		||||
	_prevWidth    uint32
 | 
			
		||||
	_prevHeight   uint32
 | 
			
		||||
	prevMsgCount  int
 | 
			
		||||
	prevPrefs     config.UserPreferences
 | 
			
		||||
 | 
			
		||||
	msgBuffer []messages.UIMessage
 | 
			
		||||
	messageIDLock sync.RWMutex
 | 
			
		||||
	messageIDs    map[string]messages.UIMessage
 | 
			
		||||
	messagesLock  sync.RWMutex
 | 
			
		||||
	messages      []messages.UIMessage
 | 
			
		||||
	msgBufferLock sync.RWMutex
 | 
			
		||||
	msgBuffer     []messages.UIMessage
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMessageView(parent *RoomView) *MessageView {
 | 
			
		||||
@@ -72,19 +78,20 @@ func NewMessageView(parent *RoomView) *MessageView {
 | 
			
		||||
		messageIDs: make(map[string]messages.UIMessage),
 | 
			
		||||
		msgBuffer:  make([]messages.UIMessage, 0),
 | 
			
		||||
 | 
			
		||||
		width:        80,
 | 
			
		||||
		widestSender: 5,
 | 
			
		||||
		prevWidth:    -1,
 | 
			
		||||
		prevHeight:   -1,
 | 
			
		||||
		prevMsgCount: -1,
 | 
			
		||||
		_width:        80,
 | 
			
		||||
		_widestSender: 5,
 | 
			
		||||
		_prevWidth:    0,
 | 
			
		||||
		_prevHeight:   0,
 | 
			
		||||
		prevMsgCount:  -1,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) updateWidestSender(sender string) {
 | 
			
		||||
	if len(sender) > view.widestSender {
 | 
			
		||||
		view.widestSender = len(sender)
 | 
			
		||||
		if view.widestSender > view.MaxSenderWidth {
 | 
			
		||||
			view.widestSender = view.MaxSenderWidth
 | 
			
		||||
	if len(sender) > int(view._widestSender) {
 | 
			
		||||
		if len(sender) > view.MaxSenderWidth {
 | 
			
		||||
			atomic.StoreUint32(&view._widestSender, uint32(view.MaxSenderWidth))
 | 
			
		||||
		} else {
 | 
			
		||||
			atomic.StoreUint32(&view._widestSender, uint32(len(sender)))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -109,22 +116,21 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction MessageDir
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var oldMsg messages.UIMessage
 | 
			
		||||
	var messageExists bool
 | 
			
		||||
	if oldMsg, messageExists = view.messageIDs[message.ID()]; messageExists {
 | 
			
		||||
	if oldMsg = view.getMessageByID(message.ID()); oldMsg != nil {
 | 
			
		||||
		view.replaceMessage(oldMsg, message)
 | 
			
		||||
		direction = IgnoreMessage
 | 
			
		||||
	} else if oldMsg, messageExists = view.messageIDs[message.TxnID()]; messageExists {
 | 
			
		||||
	} else if oldMsg = view.getMessageByID(message.TxnID()); oldMsg != nil {
 | 
			
		||||
		view.replaceMessage(oldMsg, message)
 | 
			
		||||
		delete(view.messageIDs, message.TxnID())
 | 
			
		||||
		view.deleteMessageID(message.TxnID())
 | 
			
		||||
		direction = IgnoreMessage
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	view.updateWidestSender(message.Sender())
 | 
			
		||||
 | 
			
		||||
	width := view.width
 | 
			
		||||
	width := view.width()
 | 
			
		||||
	bare := view.config.Preferences.BareMessageView
 | 
			
		||||
	if !bare {
 | 
			
		||||
		width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
 | 
			
		||||
		width -= view.TimestampWidth + TimestampSenderGap + view.widestSender() + SenderMessageGap
 | 
			
		||||
	}
 | 
			
		||||
	message.CalculateBuffer(view.config.Preferences, width)
 | 
			
		||||
 | 
			
		||||
@@ -140,18 +146,22 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction MessageDir
 | 
			
		||||
		if view.ScrollOffset > 0 {
 | 
			
		||||
			view.ScrollOffset += message.Height()
 | 
			
		||||
		}
 | 
			
		||||
		view.messagesLock.Lock()
 | 
			
		||||
		if len(view.messages) > 0 && !view.messages[len(view.messages)-1].SameDate(message) {
 | 
			
		||||
			view.messages = append(view.messages, makeDateChange(), message)
 | 
			
		||||
		} else {
 | 
			
		||||
			view.messages = append(view.messages, message)
 | 
			
		||||
		}
 | 
			
		||||
		view.messagesLock.Unlock()
 | 
			
		||||
		view.appendBuffer(message)
 | 
			
		||||
	} else if direction == PrependMessage {
 | 
			
		||||
		view.messagesLock.Lock()
 | 
			
		||||
		if len(view.messages) > 0 && !view.messages[0].SameDate(message) {
 | 
			
		||||
			view.messages = append([]messages.UIMessage{message, makeDateChange()}, view.messages...)
 | 
			
		||||
		} else {
 | 
			
		||||
			view.messages = append([]messages.UIMessage{message}, view.messages...)
 | 
			
		||||
		}
 | 
			
		||||
		view.messagesLock.Unlock()
 | 
			
		||||
	} else if oldMsg != nil {
 | 
			
		||||
		view.replaceBuffer(oldMsg, message)
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -160,31 +170,62 @@ func (view *MessageView) AddMessage(ifcMessage ifc.Message, direction MessageDir
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(message.ID()) > 0 {
 | 
			
		||||
		view.messageIDs[message.ID()] = message
 | 
			
		||||
		view.setMessageID(message)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) replaceMessage(original messages.UIMessage, new messages.UIMessage) {
 | 
			
		||||
	if len(new.ID()) > 0 {
 | 
			
		||||
		view.setMessageID(new)
 | 
			
		||||
	}
 | 
			
		||||
	view.messagesLock.Lock()
 | 
			
		||||
	for index, msg := range view.messages {
 | 
			
		||||
		if msg == original {
 | 
			
		||||
			view.messages[index] = new
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	view.messagesLock.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) getMessageByID(id string) messages.UIMessage {
 | 
			
		||||
	view.messageIDLock.RLock()
 | 
			
		||||
	defer view.messageIDLock.RUnlock()
 | 
			
		||||
	msg, ok := view.messageIDs[id]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return msg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) deleteMessageID(id string) {
 | 
			
		||||
	view.messageIDLock.Lock()
 | 
			
		||||
	delete(view.messageIDs, id)
 | 
			
		||||
	view.messageIDLock.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) setMessageID(message messages.UIMessage) {
 | 
			
		||||
	view.messageIDLock.Lock()
 | 
			
		||||
	view.messageIDs[message.ID()] = message
 | 
			
		||||
	view.messageIDLock.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) appendBuffer(message messages.UIMessage) {
 | 
			
		||||
	view.msgBufferLock.Lock()
 | 
			
		||||
	view.appendBufferUnlocked(message)
 | 
			
		||||
	view.msgBufferLock.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) appendBufferUnlocked(message messages.UIMessage) {
 | 
			
		||||
	for i := 0; i < message.Height(); i++ {
 | 
			
		||||
		view.msgBuffer = append(view.msgBuffer, message)
 | 
			
		||||
	}
 | 
			
		||||
	view.prevMsgCount++
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) replaceMessage(original messages.UIMessage, new messages.UIMessage) {
 | 
			
		||||
	if len(new.ID()) > 0 {
 | 
			
		||||
		view.messageIDs[new.ID()] = new
 | 
			
		||||
	}
 | 
			
		||||
	for index, msg := range view.messages {
 | 
			
		||||
		if msg == original {
 | 
			
		||||
			view.messages[index] = new
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages.UIMessage) {
 | 
			
		||||
	start := -1
 | 
			
		||||
	end := -1
 | 
			
		||||
	view.msgBufferLock.RLock()
 | 
			
		||||
	for index, meta := range view.msgBuffer {
 | 
			
		||||
		if meta == original {
 | 
			
		||||
			if start == -1 {
 | 
			
		||||
@@ -195,6 +236,7 @@ func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	view.msgBufferLock.RUnlock()
 | 
			
		||||
 | 
			
		||||
	if start == -1 {
 | 
			
		||||
		debug.Print("Called replaceBuffer() with message that was not in the buffer:", original)
 | 
			
		||||
@@ -208,9 +250,10 @@ func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if new.Height() == 0 {
 | 
			
		||||
		new.CalculateBuffer(view.prevPrefs, view.prevWidth)
 | 
			
		||||
		new.CalculateBuffer(view.prevPrefs, view.prevWidth())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	view.msgBufferLock.Lock()
 | 
			
		||||
	if new.Height() != end-start {
 | 
			
		||||
		metaBuffer := view.msgBuffer[0:start]
 | 
			
		||||
		for i := 0; i < new.Height(); i++ {
 | 
			
		||||
@@ -222,17 +265,20 @@ func (view *MessageView) replaceBuffer(original messages.UIMessage, new messages
 | 
			
		||||
			view.msgBuffer[i] = new
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	view.msgBufferLock.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) recalculateBuffers() {
 | 
			
		||||
	prefs := view.config.Preferences
 | 
			
		||||
	recalculateMessageBuffers := view.width != view.prevWidth ||
 | 
			
		||||
	recalculateMessageBuffers := view.width() != view.prevWidth() ||
 | 
			
		||||
		view.prevPrefs.BareMessageView != prefs.BareMessageView ||
 | 
			
		||||
		view.prevPrefs.DisableImages != prefs.DisableImages
 | 
			
		||||
	view.messagesLock.RLock()
 | 
			
		||||
	view.msgBufferLock.Lock()
 | 
			
		||||
	if recalculateMessageBuffers || len(view.messages) != view.prevMsgCount {
 | 
			
		||||
		width := view.width
 | 
			
		||||
		width := view.width()
 | 
			
		||||
		if !prefs.BareMessageView {
 | 
			
		||||
			width -= view.TimestampWidth + TimestampSenderGap + view.widestSender + SenderMessageGap
 | 
			
		||||
			width -= view.TimestampWidth + TimestampSenderGap + view.widestSender() + SenderMessageGap
 | 
			
		||||
		}
 | 
			
		||||
		view.msgBuffer = []messages.UIMessage{}
 | 
			
		||||
		view.prevMsgCount = 0
 | 
			
		||||
@@ -244,11 +290,12 @@ func (view *MessageView) recalculateBuffers() {
 | 
			
		||||
			if recalculateMessageBuffers {
 | 
			
		||||
				message.CalculateBuffer(prefs, width)
 | 
			
		||||
			}
 | 
			
		||||
			view.appendBuffer(message)
 | 
			
		||||
			view.appendBufferUnlocked(message)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	view.prevHeight = view.height
 | 
			
		||||
	view.prevWidth = view.width
 | 
			
		||||
	view.msgBufferLock.Unlock()
 | 
			
		||||
	view.messagesLock.RUnlock()
 | 
			
		||||
	view.updatePrevSize()
 | 
			
		||||
	view.prevPrefs = prefs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -309,19 +356,21 @@ func (view *MessageView) OnMouseEvent(event mauview.MouseEvent) bool {
 | 
			
		||||
		return true
 | 
			
		||||
	case tcell.Button1:
 | 
			
		||||
		x, y := event.Position()
 | 
			
		||||
		line := view.TotalHeight() - view.ScrollOffset - view.height + y
 | 
			
		||||
		line := view.TotalHeight() - view.ScrollOffset - view.Height() + y
 | 
			
		||||
		if line < 0 || line >= view.TotalHeight() {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		view.msgBufferLock.RLock()
 | 
			
		||||
		message := view.msgBuffer[line]
 | 
			
		||||
		var prevMessage messages.UIMessage
 | 
			
		||||
		if y != 0 && line > 0 {
 | 
			
		||||
			prevMessage = view.msgBuffer[line-1]
 | 
			
		||||
		}
 | 
			
		||||
		view.msgBufferLock.RUnlock()
 | 
			
		||||
 | 
			
		||||
		usernameX := view.TimestampWidth + TimestampSenderGap
 | 
			
		||||
		messageX := usernameX + view.widestSender + SenderMessageGap
 | 
			
		||||
		messageX := usernameX + view.widestSender() + SenderMessageGap
 | 
			
		||||
 | 
			
		||||
		if x >= messageX {
 | 
			
		||||
			return view.handleMessageClick(message)
 | 
			
		||||
@@ -336,30 +385,59 @@ const PaddingAtTop = 5
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) AddScrollOffset(diff int) {
 | 
			
		||||
	totalHeight := view.TotalHeight()
 | 
			
		||||
	if diff >= 0 && view.ScrollOffset+diff >= totalHeight-view.height+PaddingAtTop {
 | 
			
		||||
		view.ScrollOffset = totalHeight - view.height + PaddingAtTop
 | 
			
		||||
	height := view.Height()
 | 
			
		||||
	if diff >= 0 && view.ScrollOffset+diff >= totalHeight-height+PaddingAtTop {
 | 
			
		||||
		view.ScrollOffset = totalHeight - height + PaddingAtTop
 | 
			
		||||
	} else {
 | 
			
		||||
		view.ScrollOffset += diff
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if view.ScrollOffset > totalHeight-view.height+PaddingAtTop {
 | 
			
		||||
		view.ScrollOffset = totalHeight - view.height + PaddingAtTop
 | 
			
		||||
	if view.ScrollOffset > totalHeight-height+PaddingAtTop {
 | 
			
		||||
		view.ScrollOffset = totalHeight - height + PaddingAtTop
 | 
			
		||||
	}
 | 
			
		||||
	if view.ScrollOffset < 0 {
 | 
			
		||||
		view.ScrollOffset = 0
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) setSize(width, height int) {
 | 
			
		||||
	atomic.StoreUint32(&view._width, uint32(width))
 | 
			
		||||
	atomic.StoreUint32(&view._height, uint32(height))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) updatePrevSize() {
 | 
			
		||||
	atomic.StoreUint32(&view._prevWidth, atomic.LoadUint32(&view._width))
 | 
			
		||||
	atomic.StoreUint32(&view._prevHeight, atomic.LoadUint32(&view._height))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) prevHeight() int {
 | 
			
		||||
	return int(atomic.LoadUint32(&view._prevHeight))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) prevWidth() int {
 | 
			
		||||
	return int(atomic.LoadUint32(&view._prevWidth))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) widestSender() int {
 | 
			
		||||
	return int(atomic.LoadUint32(&view._widestSender))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) Height() int {
 | 
			
		||||
	return view.height
 | 
			
		||||
	return int(atomic.LoadUint32(&view._height))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) width() int {
 | 
			
		||||
	return int(atomic.LoadUint32(&view._width))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) TotalHeight() int {
 | 
			
		||||
	view.msgBufferLock.RLock()
 | 
			
		||||
	defer view.msgBufferLock.RUnlock()
 | 
			
		||||
	return len(view.msgBuffer)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) IsAtTop() bool {
 | 
			
		||||
	return view.ScrollOffset >= len(view.msgBuffer)-view.height+PaddingAtTop
 | 
			
		||||
	return view.ScrollOffset >= view.TotalHeight()-view.Height()+PaddingAtTop
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -407,7 +485,7 @@ func (view *MessageView) getIndexOffset(screen mauview.Screen, height, messageX
 | 
			
		||||
	indexOffset = view.TotalHeight() - view.ScrollOffset - height
 | 
			
		||||
	if indexOffset <= -PaddingAtTop {
 | 
			
		||||
		message := "Scroll up to load more messages."
 | 
			
		||||
		if view.LoadingMessages {
 | 
			
		||||
		if atomic.LoadInt32(&view.loadingMessages) == 1 {
 | 
			
		||||
			message = "Loading more messages..."
 | 
			
		||||
		}
 | 
			
		||||
		widget.WriteLineSimpleColor(screen, message, messageX, 0, tcell.ColorGreen)
 | 
			
		||||
@@ -419,6 +497,7 @@ func (view *MessageView) CapturePlaintext(height int) string {
 | 
			
		||||
	var buf strings.Builder
 | 
			
		||||
	indexOffset := view.TotalHeight() - view.ScrollOffset - height
 | 
			
		||||
	var prevMessage messages.UIMessage
 | 
			
		||||
	view.msgBufferLock.RLock()
 | 
			
		||||
	for line := 0; line < height; line++ {
 | 
			
		||||
		index := indexOffset + line
 | 
			
		||||
		if index < 0 {
 | 
			
		||||
@@ -438,27 +517,29 @@ func (view *MessageView) CapturePlaintext(height int) string {
 | 
			
		||||
			prevMessage = message
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	view.msgBufferLock.RUnlock()
 | 
			
		||||
	return buf.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) Draw(screen mauview.Screen) {
 | 
			
		||||
	view.width, view.height = screen.Size()
 | 
			
		||||
	view.setSize(screen.Size())
 | 
			
		||||
	view.recalculateBuffers()
 | 
			
		||||
 | 
			
		||||
	height := view.Height()
 | 
			
		||||
	if view.TotalHeight() == 0 {
 | 
			
		||||
		widget.WriteLineSimple(screen, "It's quite empty in here.", 0, view.height)
 | 
			
		||||
		widget.WriteLineSimple(screen, "It's quite empty in here.", 0, height)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	usernameX := view.TimestampWidth + TimestampSenderGap
 | 
			
		||||
	messageX := usernameX + view.widestSender + SenderMessageGap
 | 
			
		||||
	messageX := usernameX + view.widestSender() + SenderMessageGap
 | 
			
		||||
 | 
			
		||||
	bareMode := view.config.Preferences.BareMessageView
 | 
			
		||||
	if bareMode {
 | 
			
		||||
		messageX = 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	indexOffset := view.getIndexOffset(screen, view.height, messageX)
 | 
			
		||||
	indexOffset := view.getIndexOffset(screen, height, messageX)
 | 
			
		||||
 | 
			
		||||
	viewStart := 0
 | 
			
		||||
	if indexOffset < 0 {
 | 
			
		||||
@@ -466,13 +547,13 @@ func (view *MessageView) Draw(screen mauview.Screen) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !bareMode {
 | 
			
		||||
		separatorX := usernameX + view.widestSender + SenderSeparatorGap
 | 
			
		||||
		scrollBarHeight, scrollBarPos := view.calculateScrollBar(view.height)
 | 
			
		||||
		separatorX := usernameX + view.widestSender() + SenderSeparatorGap
 | 
			
		||||
		scrollBarHeight, scrollBarPos := view.calculateScrollBar(height)
 | 
			
		||||
 | 
			
		||||
		for line := viewStart; line < view.height; line++ {
 | 
			
		||||
		for line := viewStart; line < height; line++ {
 | 
			
		||||
			showScrollbar := line-viewStart >= scrollBarPos-scrollBarHeight && line-viewStart < scrollBarPos
 | 
			
		||||
			isTop := line == viewStart && view.ScrollOffset+view.height >= view.TotalHeight()
 | 
			
		||||
			isBottom := line == view.height-1 && view.ScrollOffset == 0
 | 
			
		||||
			isTop := line == viewStart && view.ScrollOffset+height >= view.TotalHeight()
 | 
			
		||||
			isBottom := line == height-1 && view.ScrollOffset == 0
 | 
			
		||||
 | 
			
		||||
			borderChar, borderStyle := getScrollbarStyle(showScrollbar, isTop, isBottom)
 | 
			
		||||
 | 
			
		||||
@@ -481,7 +562,8 @@ func (view *MessageView) Draw(screen mauview.Screen) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var prevMsg messages.UIMessage
 | 
			
		||||
	for line := viewStart; line < view.height && indexOffset+line < view.TotalHeight(); line++ {
 | 
			
		||||
	view.msgBufferLock.RLock()
 | 
			
		||||
	for line := viewStart; line < height && indexOffset+line < len(view.msgBuffer); line++ {
 | 
			
		||||
		index := indexOffset + line
 | 
			
		||||
 | 
			
		||||
		msg := view.msgBuffer[index]
 | 
			
		||||
@@ -493,7 +575,7 @@ func (view *MessageView) Draw(screen mauview.Screen) {
 | 
			
		||||
			//if !bareMode && (prevMsg == nil || meta.Sender() != prevMsg.Sender()) {
 | 
			
		||||
			widget.WriteLineColor(
 | 
			
		||||
				screen, mauview.AlignRight, msg.Sender(),
 | 
			
		||||
				usernameX, line, view.widestSender,
 | 
			
		||||
				usernameX, line, view.widestSender(),
 | 
			
		||||
				msg.SenderColor())
 | 
			
		||||
			//}
 | 
			
		||||
			prevMsg = msg
 | 
			
		||||
@@ -502,7 +584,8 @@ func (view *MessageView) Draw(screen mauview.Screen) {
 | 
			
		||||
		for i := index - 1; i >= 0 && view.msgBuffer[i] == msg; i-- {
 | 
			
		||||
			line--
 | 
			
		||||
		}
 | 
			
		||||
		msg.Draw(mauview.NewProxyScreen(screen, messageX, line, view.width-messageX, msg.Height()))
 | 
			
		||||
		msg.Draw(mauview.NewProxyScreen(screen, messageX, line, view.width()-messageX, msg.Height()))
 | 
			
		||||
		line += msg.Height() - 1
 | 
			
		||||
	}
 | 
			
		||||
	view.msgBufferLock.RUnlock()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ import (
 | 
			
		||||
	"math"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"maunium.net/go/mauview"
 | 
			
		||||
	"maunium.net/go/tcell"
 | 
			
		||||
@@ -29,6 +30,8 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type RoomList struct {
 | 
			
		||||
	sync.RWMutex
 | 
			
		||||
 | 
			
		||||
	parent *MainView
 | 
			
		||||
 | 
			
		||||
	// The list of tags in display order.
 | 
			
		||||
@@ -71,6 +74,8 @@ func NewRoomList(parent *MainView) *RoomList {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) Contains(roomID string) bool {
 | 
			
		||||
	list.RLock()
 | 
			
		||||
	defer list.RUnlock()
 | 
			
		||||
	for _, trl := range list.items {
 | 
			
		||||
		for _, room := range trl.All() {
 | 
			
		||||
			if room.ID == roomID {
 | 
			
		||||
@@ -88,8 +93,8 @@ func (list *RoomList) Add(room *rooms.Room) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) CheckTag(tag string) {
 | 
			
		||||
	index := list.IndexTag(tag)
 | 
			
		||||
func (list *RoomList) checkTag(tag string) {
 | 
			
		||||
	index := list.indexTag(tag)
 | 
			
		||||
 | 
			
		||||
	trl, ok := list.items[tag]
 | 
			
		||||
 | 
			
		||||
@@ -107,6 +112,8 @@ func (list *RoomList) CheckTag(tag string) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) AddToTag(tag rooms.RoomTag, room *rooms.Room) {
 | 
			
		||||
	list.Lock()
 | 
			
		||||
	defer list.Unlock()
 | 
			
		||||
	trl, ok := list.items[tag.Tag]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		list.items[tag.Tag] = NewTagRoomList(list, tag.Tag, NewDefaultOrderedRoom(room))
 | 
			
		||||
@@ -114,7 +121,7 @@ func (list *RoomList) AddToTag(tag rooms.RoomTag, room *rooms.Room) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	trl.Insert(tag.Order, room)
 | 
			
		||||
	list.CheckTag(tag.Tag)
 | 
			
		||||
	list.checkTag(tag.Tag)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) Remove(room *rooms.Room) {
 | 
			
		||||
@@ -124,6 +131,8 @@ func (list *RoomList) Remove(room *rooms.Room) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) RemoveFromTag(tag string, room *rooms.Room) {
 | 
			
		||||
	list.Lock()
 | 
			
		||||
	defer list.Unlock()
 | 
			
		||||
	trl, ok := list.items[tag]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return
 | 
			
		||||
@@ -158,10 +167,12 @@ func (list *RoomList) RemoveFromTag(tag string, room *rooms.Room) {
 | 
			
		||||
			list.selectedTag = ""
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	list.CheckTag(tag)
 | 
			
		||||
	list.checkTag(tag)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) Bump(room *rooms.Room) {
 | 
			
		||||
	list.RLock()
 | 
			
		||||
	defer list.RUnlock()
 | 
			
		||||
	for _, tag := range room.Tags() {
 | 
			
		||||
		trl, ok := list.items[tag.Tag]
 | 
			
		||||
		if !ok {
 | 
			
		||||
@@ -172,6 +183,8 @@ func (list *RoomList) Bump(room *rooms.Room) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) Clear() {
 | 
			
		||||
	list.Lock()
 | 
			
		||||
	defer list.Unlock()
 | 
			
		||||
	list.items = make(map[string]*TagRoomList)
 | 
			
		||||
	list.tags = []string{"m.favourite", "net.maunium.gomuks.fake.direct", "", "m.lowpriority"}
 | 
			
		||||
	for _, tag := range list.tags {
 | 
			
		||||
@@ -220,6 +233,8 @@ func (list *RoomList) AddScrollOffset(offset int) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) First() (string, *rooms.Room) {
 | 
			
		||||
	list.RLock()
 | 
			
		||||
	defer list.RUnlock()
 | 
			
		||||
	for _, tag := range list.tags {
 | 
			
		||||
		trl := list.items[tag]
 | 
			
		||||
		if trl.HasVisibleRooms() {
 | 
			
		||||
@@ -230,6 +245,8 @@ func (list *RoomList) First() (string, *rooms.Room) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) Last() (string, *rooms.Room) {
 | 
			
		||||
	list.RLock()
 | 
			
		||||
	defer list.RUnlock()
 | 
			
		||||
	for tagIndex := len(list.tags) - 1; tagIndex >= 0; tagIndex-- {
 | 
			
		||||
		tag := list.tags[tagIndex]
 | 
			
		||||
		trl := list.items[tag]
 | 
			
		||||
@@ -240,7 +257,7 @@ func (list *RoomList) Last() (string, *rooms.Room) {
 | 
			
		||||
	return "", nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) IndexTag(tag string) int {
 | 
			
		||||
func (list *RoomList) indexTag(tag string) int {
 | 
			
		||||
	for index, entry := range list.tags {
 | 
			
		||||
		if tag == entry {
 | 
			
		||||
			return index
 | 
			
		||||
@@ -250,6 +267,8 @@ func (list *RoomList) IndexTag(tag string) int {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) Previous() (string, *rooms.Room) {
 | 
			
		||||
	list.RLock()
 | 
			
		||||
	defer list.RUnlock()
 | 
			
		||||
	if len(list.items) == 0 {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	} else if list.selected == nil {
 | 
			
		||||
@@ -266,7 +285,7 @@ func (list *RoomList) Previous() (string, *rooms.Room) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if index == trl.Length()-1 {
 | 
			
		||||
		tagIndex := list.IndexTag(list.selectedTag)
 | 
			
		||||
		tagIndex := list.indexTag(list.selectedTag)
 | 
			
		||||
		tagIndex--
 | 
			
		||||
		for ; tagIndex >= 0; tagIndex-- {
 | 
			
		||||
			prevTag := list.tags[tagIndex]
 | 
			
		||||
@@ -283,6 +302,8 @@ func (list *RoomList) Previous() (string, *rooms.Room) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) Next() (string, *rooms.Room) {
 | 
			
		||||
	list.RLock()
 | 
			
		||||
	defer list.RUnlock()
 | 
			
		||||
	if len(list.items) == 0 {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	} else if list.selected == nil {
 | 
			
		||||
@@ -299,7 +320,7 @@ func (list *RoomList) Next() (string, *rooms.Room) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if index == 0 {
 | 
			
		||||
		tagIndex := list.IndexTag(list.selectedTag)
 | 
			
		||||
		tagIndex := list.indexTag(list.selectedTag)
 | 
			
		||||
		tagIndex++
 | 
			
		||||
		for ; tagIndex < len(list.tags); tagIndex++ {
 | 
			
		||||
			nextTag := list.tags[tagIndex]
 | 
			
		||||
@@ -325,6 +346,8 @@ func (list *RoomList) Next() (string, *rooms.Room) {
 | 
			
		||||
//
 | 
			
		||||
// TODO: Sorting. Now just finds first room with new messages.
 | 
			
		||||
func (list *RoomList) NextWithActivity() (string, *rooms.Room) {
 | 
			
		||||
	list.RLock()
 | 
			
		||||
	defer list.RUnlock()
 | 
			
		||||
	for tag, trl := range list.items {
 | 
			
		||||
		for _, room := range trl.All() {
 | 
			
		||||
			if room.HasNewMessages() {
 | 
			
		||||
@@ -337,7 +360,7 @@ func (list *RoomList) NextWithActivity() (string, *rooms.Room) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) index(tag string, room *rooms.Room) int {
 | 
			
		||||
	tagIndex := list.IndexTag(tag)
 | 
			
		||||
	tagIndex := list.indexTag(tag)
 | 
			
		||||
	if tagIndex == -1 {
 | 
			
		||||
		return -1
 | 
			
		||||
	}
 | 
			
		||||
@@ -358,6 +381,7 @@ func (list *RoomList) index(tag string, room *rooms.Room) int {
 | 
			
		||||
	if tagIndex > 0 {
 | 
			
		||||
		for i := 0; i < tagIndex; i++ {
 | 
			
		||||
			prevTag := list.tags[i]
 | 
			
		||||
 | 
			
		||||
			prevTRL := list.items[prevTag]
 | 
			
		||||
			localIndex += prevTRL.RenderHeight()
 | 
			
		||||
		}
 | 
			
		||||
@@ -367,9 +391,11 @@ func (list *RoomList) index(tag string, room *rooms.Room) int {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (list *RoomList) ContentHeight() (height int) {
 | 
			
		||||
	list.RLock()
 | 
			
		||||
	for _, tag := range list.tags {
 | 
			
		||||
		height += list.items[tag].RenderHeight()
 | 
			
		||||
	}
 | 
			
		||||
	list.RUnlock()
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -410,6 +436,8 @@ func (list *RoomList) clickRoom(line, column int, mod bool) bool {
 | 
			
		||||
	if line < 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	list.RLock()
 | 
			
		||||
	defer list.RUnlock()
 | 
			
		||||
	for _, tag := range list.tags {
 | 
			
		||||
		trl := list.items[tag]
 | 
			
		||||
		if line--; line == -1 {
 | 
			
		||||
@@ -484,6 +512,7 @@ func (list *RoomList) Draw(screen mauview.Screen) {
 | 
			
		||||
	y -= list.scrollOffset
 | 
			
		||||
 | 
			
		||||
	// Draw the list items.
 | 
			
		||||
	list.RLock()
 | 
			
		||||
	for _, tag := range list.tags {
 | 
			
		||||
		trl := list.items[tag]
 | 
			
		||||
		tagDisplayName := list.GetTagDisplayName(tag)
 | 
			
		||||
@@ -501,4 +530,5 @@ func (list *RoomList) Draw(screen mauview.Screen) {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	list.RUnlock()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -277,7 +277,7 @@ func (trl *TagRoomList) Draw(screen mauview.Screen) {
 | 
			
		||||
	screen.SetCell(width-1, 0, tcell.StyleDefault, '▼')
 | 
			
		||||
 | 
			
		||||
	y := 1
 | 
			
		||||
	for i := trl.Length() - 1; i >= 0; i-- {
 | 
			
		||||
	for i := len(items) - 1; i >= 0; i-- {
 | 
			
		||||
		if y >= height {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										115
									
								
								ui/view-main.go
									
									
									
									
									
								
							
							
						
						
									
										115
									
								
								ui/view-main.go
									
									
									
									
									
								
							@@ -20,6 +20,8 @@ import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unicode"
 | 
			
		||||
 | 
			
		||||
@@ -42,6 +44,7 @@ type MainView struct {
 | 
			
		||||
	roomView     *mauview.Box
 | 
			
		||||
	currentRoom  *RoomView
 | 
			
		||||
	rooms        map[string]*RoomView
 | 
			
		||||
	roomsLock    sync.RWMutex
 | 
			
		||||
	cmdProcessor *CommandProcessor
 | 
			
		||||
	focused      mauview.Focusable
 | 
			
		||||
 | 
			
		||||
@@ -245,13 +248,17 @@ func (view *MainView) Blur() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) SwitchRoom(tag string, room *rooms.Room) {
 | 
			
		||||
	view.switchRoom(tag, room, true)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) switchRoom(tag string, room *rooms.Room, lock bool) {
 | 
			
		||||
	if room == nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	roomView := view.rooms[room.ID]
 | 
			
		||||
	if roomView == nil {
 | 
			
		||||
		debug.Print("Tried to switch to non-nil room with nil roomView!")
 | 
			
		||||
	roomView, ok := view.getRoomView(room.ID, lock)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		debug.Print("Tried to switch to room with nonexistent roomView!")
 | 
			
		||||
		debug.Print(tag, room)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -265,7 +272,7 @@ func (view *MainView) SwitchRoom(tag string, room *rooms.Room) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) addRoomPage(room *rooms.Room) {
 | 
			
		||||
func (view *MainView) addRoomPage(room *rooms.Room) *RoomView {
 | 
			
		||||
	if _, ok := view.rooms[room.ID]; !ok {
 | 
			
		||||
		roomView := NewRoomView(view, room).
 | 
			
		||||
			SetInputChangedFunc(view.InputChanged)
 | 
			
		||||
@@ -276,53 +283,73 @@ func (view *MainView) addRoomPage(room *rooms.Room) {
 | 
			
		||||
		if len(roomView.MessageView().messages) == 0 {
 | 
			
		||||
			go view.LoadHistory(room.ID)
 | 
			
		||||
		}
 | 
			
		||||
		return roomView
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) GetRoom(roomID string) ifc.RoomView {
 | 
			
		||||
	room, ok := view.rooms[roomID]
 | 
			
		||||
	room, ok := view.getRoomView(roomID, true)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		view.AddRoom(view.matrix.GetRoom(roomID))
 | 
			
		||||
		room, ok := view.rooms[roomID]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		return room
 | 
			
		||||
		return view.addRoom(view.matrix.GetRoom(roomID))
 | 
			
		||||
	}
 | 
			
		||||
	return room
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) getRoomView(roomID string, lock bool) (room *RoomView, ok bool) {
 | 
			
		||||
	if lock {
 | 
			
		||||
		view.roomsLock.RLock()
 | 
			
		||||
		room, ok = view.rooms[roomID]
 | 
			
		||||
		view.roomsLock.RUnlock()
 | 
			
		||||
	} else {
 | 
			
		||||
		room, ok = view.rooms[roomID]
 | 
			
		||||
	}
 | 
			
		||||
	return room, ok
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) AddRoom(room *rooms.Room) {
 | 
			
		||||
	if view.roomList.Contains(room.ID) {
 | 
			
		||||
		debug.Print("Add aborted (room exists)", room.ID, room.GetTitle())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	debug.Print("Adding", room.ID, room.GetTitle())
 | 
			
		||||
	view.roomList.Add(room)
 | 
			
		||||
	view.addRoomPage(room)
 | 
			
		||||
	if !view.roomList.HasSelected() {
 | 
			
		||||
		view.SwitchRoom(view.roomList.First())
 | 
			
		||||
	}
 | 
			
		||||
	view.addRoom(room)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) RemoveRoom(room *rooms.Room) {
 | 
			
		||||
	roomView := view.GetRoom(room.ID)
 | 
			
		||||
	if roomView == nil {
 | 
			
		||||
	view.roomsLock.Lock()
 | 
			
		||||
	_, ok := view.getRoomView(room.ID, false)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		view.roomsLock.Unlock()
 | 
			
		||||
		debug.Print("Remove aborted (not found)", room.ID, room.GetTitle())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	debug.Print("Removing", room.ID, room.GetTitle())
 | 
			
		||||
 | 
			
		||||
	view.roomList.Remove(room)
 | 
			
		||||
	view.SwitchRoom(view.roomList.Selected())
 | 
			
		||||
 | 
			
		||||
	t, r := view.roomList.Selected()
 | 
			
		||||
	view.switchRoom(t, r, false)
 | 
			
		||||
	delete(view.rooms, room.ID)
 | 
			
		||||
	view.roomsLock.Unlock()
 | 
			
		||||
 | 
			
		||||
	view.parent.Render()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) addRoom(room *rooms.Room) *RoomView {
 | 
			
		||||
	if view.roomList.Contains(room.ID) {
 | 
			
		||||
		debug.Print("Add aborted (room exists)", room.ID, room.GetTitle())
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	debug.Print("Adding", room.ID, room.GetTitle())
 | 
			
		||||
	view.roomList.Add(room)
 | 
			
		||||
	view.roomsLock.Lock()
 | 
			
		||||
	roomView := view.addRoomPage(room)
 | 
			
		||||
	if !view.roomList.HasSelected() {
 | 
			
		||||
		t, r := view.roomList.First()
 | 
			
		||||
		view.switchRoom(t, r, false)
 | 
			
		||||
	}
 | 
			
		||||
	view.roomsLock.Unlock()
 | 
			
		||||
	return roomView
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) SetRooms(rooms map[string]*rooms.Room) {
 | 
			
		||||
	view.roomList.Clear()
 | 
			
		||||
	view.roomsLock.Lock()
 | 
			
		||||
	view.rooms = make(map[string]*RoomView)
 | 
			
		||||
	for _, room := range rooms {
 | 
			
		||||
		if room.HasLeft {
 | 
			
		||||
@@ -331,7 +358,9 @@ func (view *MainView) SetRooms(rooms map[string]*rooms.Room) {
 | 
			
		||||
		view.roomList.Add(room)
 | 
			
		||||
		view.addRoomPage(room)
 | 
			
		||||
	}
 | 
			
		||||
	view.SwitchRoom(view.roomList.First())
 | 
			
		||||
	t, r := view.roomList.First()
 | 
			
		||||
	view.switchRoom(t, r, false)
 | 
			
		||||
	view.roomsLock.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) UpdateTags(room *rooms.Room) {
 | 
			
		||||
@@ -342,8 +371,8 @@ func (view *MainView) UpdateTags(room *rooms.Room) {
 | 
			
		||||
	view.roomList.Add(room)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) SetTyping(room string, users []string) {
 | 
			
		||||
	roomView, ok := view.rooms[room]
 | 
			
		||||
func (view *MainView) SetTyping(roomID string, users []string) {
 | 
			
		||||
	roomView, ok := view.getRoomView(roomID, true)
 | 
			
		||||
	if ok {
 | 
			
		||||
		roomView.SetTyping(users)
 | 
			
		||||
		view.parent.Render()
 | 
			
		||||
@@ -392,33 +421,27 @@ func (view *MainView) NotifyMessage(room *rooms.Room, message ifc.Message, shoul
 | 
			
		||||
 | 
			
		||||
func (view *MainView) InitialSyncDone() {
 | 
			
		||||
	view.roomList.Clear()
 | 
			
		||||
	view.roomsLock.RLock()
 | 
			
		||||
	for _, room := range view.rooms {
 | 
			
		||||
		view.roomList.Add(room.Room)
 | 
			
		||||
		room.UpdateUserList()
 | 
			
		||||
	}
 | 
			
		||||
	view.roomsLock.RUnlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) LoadHistory(room string) {
 | 
			
		||||
func (view *MainView) LoadHistory(roomID string) {
 | 
			
		||||
	defer debug.Recover()
 | 
			
		||||
	roomView := view.rooms[room]
 | 
			
		||||
	msgView := roomView.MessageView()
 | 
			
		||||
 | 
			
		||||
	batch := roomView.Room.PrevBatch
 | 
			
		||||
	lockTime := time.Now().Unix() + 1
 | 
			
		||||
 | 
			
		||||
	roomView.Room.LockHistory()
 | 
			
		||||
	msgView.LoadingMessages = true
 | 
			
		||||
	defer func() {
 | 
			
		||||
		roomView.Room.UnlockHistory()
 | 
			
		||||
		msgView.LoadingMessages = false
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	// There's no clean way to try to lock a mutex, so we just check if we still
 | 
			
		||||
	// want to continue after we get the lock. This function should always be ran
 | 
			
		||||
	// in a goroutine, so the blocking doesn't matter.
 | 
			
		||||
	if time.Now().Unix() >= lockTime || batch != roomView.Room.PrevBatch {
 | 
			
		||||
	roomView, ok := view.getRoomView(roomID, true)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	msgView := roomView.MessageView()
 | 
			
		||||
 | 
			
		||||
	if !atomic.CompareAndSwapInt32(&msgView.loadingMessages, 0, 1) {
 | 
			
		||||
		// Locked
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer atomic.StoreInt32(&msgView.loadingMessages, 0)
 | 
			
		||||
 | 
			
		||||
	history, err := view.matrix.GetHistory(roomView.Room, 50)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user