Refactoring, right-align users and fix join/leave messages
This commit is contained in:
		
							
								
								
									
										61
									
								
								matrix.go
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								matrix.go
									
									
									
									
									
								
							@@ -121,18 +121,19 @@ func (c *MatrixContainer) UpdateRoomList() {
 | 
			
		||||
 | 
			
		||||
func (c *MatrixContainer) Start() {
 | 
			
		||||
	defer c.gmx.Recover()
 | 
			
		||||
	c.debug.Print("Starting sync...")
 | 
			
		||||
	c.running = true
 | 
			
		||||
	c.ui.SetView(ViewMain)
 | 
			
		||||
	c.client.Store = c.config.Session
 | 
			
		||||
 | 
			
		||||
	c.UpdateRoomList()
 | 
			
		||||
 | 
			
		||||
	syncer := c.client.Syncer.(*gomatrix.DefaultSyncer)
 | 
			
		||||
	syncer := gomatrix.NewDefaultSyncer(c.config.Session.MXID, c.config.Session)
 | 
			
		||||
	syncer.OnEventType("m.room.message", c.HandleMessage)
 | 
			
		||||
	syncer.OnEventType("m.room.member", c.HandleMembership)
 | 
			
		||||
	syncer.OnEventType("m.typing", c.HandleTyping)
 | 
			
		||||
	c.client.Syncer = syncer
 | 
			
		||||
 | 
			
		||||
	c.UpdateRoomList()
 | 
			
		||||
 | 
			
		||||
	c.debug.Print("Starting sync...")
 | 
			
		||||
	c.running = true
 | 
			
		||||
	c.ui.SetView(ViewMain)
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-c.stop:
 | 
			
		||||
@@ -152,17 +153,23 @@ func (c *MatrixContainer) Start() {
 | 
			
		||||
func (c *MatrixContainer) HandleMessage(evt *gomatrix.Event) {
 | 
			
		||||
	message, _ := evt.Content["body"].(string)
 | 
			
		||||
 | 
			
		||||
	timestamp := time.Now()
 | 
			
		||||
	if evt.Timestamp != 0 {
 | 
			
		||||
		timestamp = time.Unix(evt.Timestamp/1000, evt.Timestamp%1000*1000)
 | 
			
		||||
	room := c.ui.MainView().GetRoom(evt.RoomID)
 | 
			
		||||
	if room != nil {
 | 
			
		||||
		room.AddMessage(evt.ID, evt.Sender, message, unixToTime(evt.Timestamp))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	c.ui.MainView().AddRealMessage(evt.RoomID, evt.ID, evt.Sender, message, timestamp)
 | 
			
		||||
func unixToTime(unix int64) time.Time {
 | 
			
		||||
	timestamp := time.Now()
 | 
			
		||||
	if unix != 0 {
 | 
			
		||||
		timestamp = time.Unix(unix/1000, unix%1000*1000)
 | 
			
		||||
	}
 | 
			
		||||
	return timestamp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *MatrixContainer) HandleMembership(evt *gomatrix.Event) {
 | 
			
		||||
	membership, _ := evt.Content["membership"].(string)
 | 
			
		||||
	if evt.StateKey != nil && *evt.StateKey == c.config.Session.MXID {
 | 
			
		||||
		membership, _ := evt.Content["membership"].(string)
 | 
			
		||||
		prevMembership := "leave"
 | 
			
		||||
		if evt.Unsigned.PrevContent != nil {
 | 
			
		||||
			prevMembership, _ = evt.Unsigned.PrevContent["membership"].(string)
 | 
			
		||||
@@ -175,6 +182,34 @@ func (c *MatrixContainer) HandleMembership(evt *gomatrix.Event) {
 | 
			
		||||
		} else if membership == "leave" {
 | 
			
		||||
			c.ui.MainView().RemoveRoom(evt.RoomID)
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	room := c.ui.MainView().GetRoom(evt.RoomID)
 | 
			
		||||
 | 
			
		||||
	// TODO this shouldn't be necessary
 | 
			
		||||
	room.room.UpdateState(evt)
 | 
			
		||||
 | 
			
		||||
	if room != nil {
 | 
			
		||||
		var message, sender string
 | 
			
		||||
		if membership == "invite" {
 | 
			
		||||
			sender = "---"
 | 
			
		||||
			message = fmt.Sprintf("%s invited %s.", evt.Sender, *evt.StateKey)
 | 
			
		||||
		} else if membership == "join" {
 | 
			
		||||
			sender = "-->"
 | 
			
		||||
			message = fmt.Sprintf("%s joined the room.", *evt.StateKey)
 | 
			
		||||
		} else if membership == "leave" {
 | 
			
		||||
			sender = "<--"
 | 
			
		||||
			if evt.Sender != *evt.StateKey {
 | 
			
		||||
				reason, _ := evt.Content["reason"].(string)
 | 
			
		||||
				message = fmt.Sprintf("%s kicked %s: %s", evt.Sender, *evt.StateKey, reason)
 | 
			
		||||
			} else {
 | 
			
		||||
				message = fmt.Sprintf("%s left the room.", *evt.StateKey)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		room.UpdateUserList()
 | 
			
		||||
		room.AddMessage(evt.ID, sender, message, unixToTime(evt.Timestamp))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -240,8 +275,8 @@ func (c *MatrixContainer) getState(roomID string) []*gomatrix.Event {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *MatrixContainer) GetRoom(roomID string) *gomatrix.Room {
 | 
			
		||||
	room := c.client.Store.LoadRoom(roomID)
 | 
			
		||||
	if len(room.State) == 0 {
 | 
			
		||||
	room := c.config.Session.LoadRoom(roomID)
 | 
			
		||||
	if room != nil && len(room.State) == 0 {
 | 
			
		||||
		events := c.getState(room.ID)
 | 
			
		||||
		if events != nil {
 | 
			
		||||
			for _, event := range events {
 | 
			
		||||
 
 | 
			
		||||
@@ -93,11 +93,9 @@ type MessageView struct {
 | 
			
		||||
	totalHeight         int
 | 
			
		||||
 | 
			
		||||
	messages []*Message
 | 
			
		||||
 | 
			
		||||
	debug DebugPrinter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMessageView(debug DebugPrinter) *MessageView {
 | 
			
		||||
func NewMessageView() *MessageView {
 | 
			
		||||
	return &MessageView{
 | 
			
		||||
		Box:             tview.NewBox(),
 | 
			
		||||
		MaxSenderWidth:  20,
 | 
			
		||||
@@ -113,8 +111,6 @@ func NewMessageView(debug DebugPrinter) *MessageView {
 | 
			
		||||
		firstDisplayMessage: -1,
 | 
			
		||||
		lastDisplayMessage:  -1,
 | 
			
		||||
		totalHeight:         -1,
 | 
			
		||||
 | 
			
		||||
		debug: debug,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -207,6 +203,24 @@ func (view *MessageView) writeLine(screen tcell.Screen, line string, x, y int, c
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MessageView) writeLineRight(screen tcell.Screen, line string, x, y, maxWidth int, color tcell.Color) {
 | 
			
		||||
	offsetX := maxWidth - runewidth.StringWidth(line)
 | 
			
		||||
	if offsetX < 0 {
 | 
			
		||||
		offsetX = 0
 | 
			
		||||
	}
 | 
			
		||||
	for _, ch := range line {
 | 
			
		||||
		chWidth := runewidth.RuneWidth(ch)
 | 
			
		||||
		if chWidth == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for localOffset := 0; localOffset < chWidth; localOffset++ {
 | 
			
		||||
			screen.SetContent(x+offsetX+localOffset, y, ch, nil, tcell.StyleDefault.Foreground(color))
 | 
			
		||||
		}
 | 
			
		||||
		offsetX += chWidth
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	TimestampSenderGap = 1
 | 
			
		||||
	SenderSeparatorGap = 1
 | 
			
		||||
@@ -246,7 +260,9 @@ func (view *MessageView) Draw(screen tcell.Screen) {
 | 
			
		||||
		}
 | 
			
		||||
		view.writeLine(screen, message.Timestamp, x, senderAtLine, tcell.ColorDefault)
 | 
			
		||||
		if message.RenderSender || i == view.lastDisplayMessage {
 | 
			
		||||
			view.writeLine(screen, message.Sender, x+usernameOffsetX, senderAtLine, message.senderColor)
 | 
			
		||||
			view.writeLineRight(screen, message.Sender,
 | 
			
		||||
				x+usernameOffsetX, senderAtLine,
 | 
			
		||||
				view.widestSender, message.senderColor)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for num, line := range message.buffer {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										64
									
								
								room-view.go
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								room-view.go
									
									
									
									
									
								
							@@ -21,6 +21,7 @@ import (
 | 
			
		||||
	"hash/fnv"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/gdamore/tcell"
 | 
			
		||||
	"maunium.net/go/gomatrix"
 | 
			
		||||
@@ -36,7 +37,7 @@ type RoomView struct {
 | 
			
		||||
	userList *tview.TextView
 | 
			
		||||
	room     *gomatrix.Room
 | 
			
		||||
 | 
			
		||||
	debug DebugPrinter
 | 
			
		||||
	parent *MainView
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var colorNames []string
 | 
			
		||||
@@ -51,15 +52,15 @@ func init() {
 | 
			
		||||
	sort.Sort(sort.StringSlice(colorNames))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewRoomView(debug DebugPrinter, room *gomatrix.Room) *RoomView {
 | 
			
		||||
func NewRoomView(parent *MainView, room *gomatrix.Room) *RoomView {
 | 
			
		||||
	view := &RoomView{
 | 
			
		||||
		Box:      tview.NewBox(),
 | 
			
		||||
		topic:    tview.NewTextView(),
 | 
			
		||||
		content:  NewMessageView(debug),
 | 
			
		||||
		content:  NewMessageView(),
 | 
			
		||||
		status:   tview.NewTextView(),
 | 
			
		||||
		userList: tview.NewTextView(),
 | 
			
		||||
		room:     room,
 | 
			
		||||
		debug:    debug,
 | 
			
		||||
		parent:   parent,
 | 
			
		||||
	}
 | 
			
		||||
	view.topic.
 | 
			
		||||
		SetText(strings.Replace(room.GetTopic(), "\n", " ", -1)).
 | 
			
		||||
@@ -108,20 +109,38 @@ func (view *RoomView) SetTyping(users []string) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *RoomView) AutocompleteUser(existingText string) (completions []string) {
 | 
			
		||||
	for _, user := range view.room.GetMembers() {
 | 
			
		||||
		if strings.HasPrefix(user.DisplayName, existingText) {
 | 
			
		||||
			completions = append(completions, user.DisplayName)
 | 
			
		||||
		} else if strings.HasPrefix(user.UserID, existingText) {
 | 
			
		||||
			completions = append(completions, user.UserID)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *RoomView) MessageView() *MessageView {
 | 
			
		||||
	return view.content
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getColorName(s string) string {
 | 
			
		||||
	h := fnv.New32a()
 | 
			
		||||
	h.Write([]byte(s))
 | 
			
		||||
	return colorNames[int(h.Sum32())%len(colorNames)]
 | 
			
		||||
	switch s {
 | 
			
		||||
	case "-->":
 | 
			
		||||
		return "green"
 | 
			
		||||
	case "<--":
 | 
			
		||||
		return "red"
 | 
			
		||||
	case "---":
 | 
			
		||||
		return "yellow"
 | 
			
		||||
	default:
 | 
			
		||||
		h := fnv.New32a()
 | 
			
		||||
		h.Write([]byte(s))
 | 
			
		||||
		return colorNames[int(h.Sum32())%len(colorNames)]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getColor(s string) tcell.Color {
 | 
			
		||||
	h := fnv.New32a()
 | 
			
		||||
	h.Write([]byte(s))
 | 
			
		||||
	return tcell.ColorNames[colorNames[int(h.Sum32())%len(colorNames)]]
 | 
			
		||||
	return tcell.ColorNames[getColorName(s)]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func color(s string) string {
 | 
			
		||||
@@ -129,12 +148,29 @@ func color(s string) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *RoomView) UpdateUserList() {
 | 
			
		||||
	var buf strings.Builder
 | 
			
		||||
	var joined strings.Builder
 | 
			
		||||
	var invited strings.Builder
 | 
			
		||||
	for _, user := range view.room.GetMembers() {
 | 
			
		||||
		if user.Membership == "join" {
 | 
			
		||||
			buf.WriteString(color(user.DisplayName))
 | 
			
		||||
			buf.WriteRune('\n')
 | 
			
		||||
			joined.WriteString(color(user.DisplayName))
 | 
			
		||||
			joined.WriteRune('\n')
 | 
			
		||||
		} else if user.Membership == "invite" {
 | 
			
		||||
			invited.WriteString(color(user.DisplayName))
 | 
			
		||||
			invited.WriteRune('\n')
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	view.userList.SetText(buf.String())
 | 
			
		||||
	view.userList.Clear()
 | 
			
		||||
	fmt.Fprintf(view.userList, "%s\n", joined.String())
 | 
			
		||||
	if invited.Len() > 0 {
 | 
			
		||||
		fmt.Fprintf(view.userList, "\nInvited:\n%s", invited.String())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *RoomView) AddMessage(id, sender, message string, timestamp time.Time) {
 | 
			
		||||
	member := view.room.GetMember(sender)
 | 
			
		||||
	if member != nil {
 | 
			
		||||
		sender = member.DisplayName
 | 
			
		||||
	}
 | 
			
		||||
	view.content.AddMessage(id, sender, message, timestamp)
 | 
			
		||||
	view.parent.Render()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -86,8 +86,8 @@ func (s *Session) LoadNextBatch(_ string) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Session) LoadRoom(mxid string) *gomatrix.Room {
 | 
			
		||||
	room, ok := s.Rooms[mxid]
 | 
			
		||||
	if !ok || room == nil {
 | 
			
		||||
	room, _ := s.Rooms[mxid]
 | 
			
		||||
	if room == nil {
 | 
			
		||||
		room = gomatrix.NewRoom(mxid)
 | 
			
		||||
		s.SaveRoom(room)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								view-main.go
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								view-main.go
									
									
									
									
									
								
							@@ -111,15 +111,8 @@ func findWordToTabComplete(text string) string {
 | 
			
		||||
	return output
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *RoomView) AutocompleteUser(existingText string) (completions []string) {
 | 
			
		||||
	for _, user := range view.room.GetMembers() {
 | 
			
		||||
		if strings.HasPrefix(user.DisplayName, existingText) {
 | 
			
		||||
			completions = append(completions, user.DisplayName)
 | 
			
		||||
		} else if strings.HasPrefix(user.UserID, existingText) {
 | 
			
		||||
			completions = append(completions, user.UserID)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
func (view *MainView) GetRoom(id string) *RoomView {
 | 
			
		||||
	return view.rooms[id]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) InputTabComplete(text string, cursorOffset int) string {
 | 
			
		||||
@@ -231,7 +224,7 @@ func (view *MainView) addRoom(index int, room string) {
 | 
			
		||||
		view.SwitchRoom(index)
 | 
			
		||||
	})
 | 
			
		||||
	if !view.roomView.HasPage(room) {
 | 
			
		||||
		roomView := NewRoomView(view.debug, roomStore)
 | 
			
		||||
		roomView := NewRoomView(view, roomStore)
 | 
			
		||||
		view.rooms[room] = roomView
 | 
			
		||||
		view.roomView.AddPage(room, roomView, true, false)
 | 
			
		||||
		roomView.UpdateUserList()
 | 
			
		||||
@@ -285,17 +278,13 @@ func (view *MainView) SetTyping(room string, users []string) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) AddMessage(room, message string) {
 | 
			
		||||
	view.AddRealMessage(room, "", "*", message, time.Now())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) AddRealMessage(room, id, sender, message string, timestamp time.Time) {
 | 
			
		||||
	roomView, ok := view.rooms[room]
 | 
			
		||||
	if ok {
 | 
			
		||||
		member := roomView.room.GetMember(sender)
 | 
			
		||||
		if member != nil {
 | 
			
		||||
			sender = member.DisplayName
 | 
			
		||||
		}
 | 
			
		||||
		roomView.content.AddMessage(id, sender, message, timestamp)
 | 
			
		||||
		roomView.content.AddMessage("", "*", message, time.Now())
 | 
			
		||||
		view.parent.Render()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (view *MainView) Render() {
 | 
			
		||||
	view.parent.Render()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user