Handle tag events
This commit is contained in:
		| @@ -54,6 +54,8 @@ type MainView interface { | |||||||
| 	SetRooms(roomIDs []string) | 	SetRooms(roomIDs []string) | ||||||
| 	SaveAllHistory() | 	SaveAllHistory() | ||||||
|  |  | ||||||
|  | 	UpdateTags(room *rooms.Room, newTags []rooms.RoomTag) | ||||||
|  |  | ||||||
| 	SetTyping(roomID string, users []string) | 	SetTyping(roomID string, users []string) | ||||||
| 	ParseEvent(roomView RoomView, evt *gomatrix.Event) Message | 	ParseEvent(roomView RoomView, evt *gomatrix.Event) Message | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,7 +18,6 @@ package matrix | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| @@ -255,9 +254,23 @@ func (c *Container) HandlePushRules(evt *gomatrix.Event) { | |||||||
|  |  | ||||||
| // HandleTag is the event handler for the m.tag account data event. | // HandleTag is the event handler for the m.tag account data event. | ||||||
| func (c *Container) HandleTag(evt *gomatrix.Event) { | func (c *Container) HandleTag(evt *gomatrix.Event) { | ||||||
| 	debug.Print("Received updated tags for", evt.RoomID) | 	room := c.config.Session.GetRoom(evt.RoomID) | ||||||
| 	dat, _ := json.MarshalIndent(&evt.Content, "", "  ") |  | ||||||
| 	debug.Print(string(dat)) | 	tags, _ := evt.Content["tags"].(map[string]interface{}) | ||||||
|  | 	newTags := make([]rooms.RoomTag, len(tags)) | ||||||
|  | 	index := 0 | ||||||
|  | 	for tag, infoifc := range tags { | ||||||
|  | 		info, _ := infoifc.(map[string]interface{}) | ||||||
|  | 		order, _ := info["order"].(float64) | ||||||
|  | 		newTags[index] = rooms.RoomTag{ | ||||||
|  | 			Tag:   tag, | ||||||
|  | 			Order: order, | ||||||
|  | 		} | ||||||
|  | 		index++ | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	mainView := c.ui.MainView() | ||||||
|  | 	mainView.UpdateTags(room, newTags) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) { | func (c *Container) processOwnMembershipChange(evt *gomatrix.Event) { | ||||||
|   | |||||||
| @@ -34,6 +34,14 @@ const ( | |||||||
| 	MemberRoomName | 	MemberRoomName | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | // RoomTag is a tag given to a specific room. | ||||||
|  | type RoomTag struct { | ||||||
|  | 	// The name of the tag. | ||||||
|  | 	Tag string | ||||||
|  | 	// The order of the tag. Smaller values are ordered higher. | ||||||
|  | 	Order float64 | ||||||
|  | } | ||||||
|  |  | ||||||
| // Room represents a single Matrix room. | // Room represents a single Matrix room. | ||||||
| type Room struct { | type Room struct { | ||||||
| 	*gomatrix.Room | 	*gomatrix.Room | ||||||
| @@ -53,7 +61,9 @@ type Room struct { | |||||||
| 	// a notificationless message like bot notices. | 	// a notificationless message like bot notices. | ||||||
| 	HasNewMessages bool | 	HasNewMessages bool | ||||||
|  |  | ||||||
| 	Tags []string | 	// List of tags given to this room | ||||||
|  | 	RawTags []RoomTag | ||||||
|  | 	// Timestamp of previously received actual message. | ||||||
| 	LastReceivedMessage time.Time | 	LastReceivedMessage time.Time | ||||||
|  |  | ||||||
| 	// MXID -> Member cache calculated from membership events. | 	// MXID -> Member cache calculated from membership events. | ||||||
| @@ -102,6 +112,13 @@ func (room *Room) MarkRead() { | |||||||
| 	room.HasNewMessages = false | 	room.HasNewMessages = false | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (room *Room) Tags() []RoomTag { | ||||||
|  | 	if len(room.RawTags) == 0 { | ||||||
|  | 		return []RoomTag{{"", 0.5}} | ||||||
|  | 	} | ||||||
|  | 	return room.RawTags | ||||||
|  | } | ||||||
|  |  | ||||||
| // UpdateState updates the room's current state with the given Event. This will clobber events based | // UpdateState updates the room's current state with the given Event. This will clobber events based | ||||||
| // on the type/state_key combination. | // on the type/state_key combination. | ||||||
| func (room *Room) UpdateState(event *gomatrix.Event) { | func (room *Room) UpdateState(event *gomatrix.Event) { | ||||||
|   | |||||||
							
								
								
									
										292
									
								
								ui/room-list.go
									
									
									
									
									
								
							
							
						
						
									
										292
									
								
								ui/room-list.go
									
									
									
									
									
								
							| @@ -18,7 +18,9 @@ package ui | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"regexp" | ||||||
| 	"strconv" | 	"strconv" | ||||||
|  | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"maunium.net/go/gomuks/matrix/rooms" | 	"maunium.net/go/gomuks/matrix/rooms" | ||||||
| @@ -27,13 +29,21 @@ import ( | |||||||
| 	"maunium.net/go/tview" | 	"maunium.net/go/tview" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | type roomListItem struct { | ||||||
|  | 	room     *rooms.Room | ||||||
|  | 	priority float64 | ||||||
|  | } | ||||||
|  |  | ||||||
| type RoomList struct { | type RoomList struct { | ||||||
| 	*tview.Box | 	*tview.Box | ||||||
|  |  | ||||||
|  | 	// The list of tags in display order. | ||||||
|  | 	tags []string | ||||||
| 	// The list of rooms, in reverse order. | 	// The list of rooms, in reverse order. | ||||||
| 	items []*rooms.Room | 	items map[string][]*rooms.Room | ||||||
| 	// The selected room. | 	// The selected room. | ||||||
| 	selected    *rooms.Room | 	selected    *rooms.Room | ||||||
|  | 	selectedTag string | ||||||
|  |  | ||||||
| 	// The item main text color. | 	// The item main text color. | ||||||
| 	mainTextColor tcell.Color | 	mainTextColor tcell.Color | ||||||
| @@ -46,7 +56,7 @@ type RoomList struct { | |||||||
| func NewRoomList() *RoomList { | func NewRoomList() *RoomList { | ||||||
| 	return &RoomList{ | 	return &RoomList{ | ||||||
| 		Box:   tview.NewBox(), | 		Box:   tview.NewBox(), | ||||||
| 		items: []*rooms.Room{}, | 		items: make(map[string][]*rooms.Room), | ||||||
|  |  | ||||||
| 		mainTextColor:           tcell.ColorWhite, | 		mainTextColor:           tcell.ColorWhite, | ||||||
| 		selectedTextColor:       tcell.ColorWhite, | 		selectedTextColor:       tcell.ColorWhite, | ||||||
| @@ -55,107 +65,248 @@ func NewRoomList() *RoomList { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) Contains(roomID string) bool { | func (list *RoomList) Contains(roomID string) bool { | ||||||
| 	for _, room := range list.items { | 	for _, roomList := range list.items { | ||||||
|  | 		for _, room := range roomList { | ||||||
| 			if room.ID == roomID { | 			if room.ID == roomID { | ||||||
| 				return true | 				return true | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 	return false | 	return false | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) Add(room *rooms.Room) { | func (list *RoomList) Add(room *rooms.Room) { | ||||||
| 	list.items = append(list.items, nil) | 	for _, tag := range room.Tags() { | ||||||
| 	insertAt := len(list.items) - 1 | 		list.AddToTag(tag.Tag, room) | ||||||
| 	for i := 0; i < len(list.items)-1; i++ { | 	} | ||||||
| 		if list.items[i].LastReceivedMessage.After(room.LastReceivedMessage) { | } | ||||||
|  |  | ||||||
|  | func (list *RoomList) CheckTag(tag string) { | ||||||
|  | 	index := list.IndexTag(tag) | ||||||
|  |  | ||||||
|  | 	items, ok := list.items[tag] | ||||||
|  |  | ||||||
|  | 	if len(items) == 0 { | ||||||
|  | 		delete(list.items, tag) | ||||||
|  | 		ok = false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if ok && index == -1 { | ||||||
|  | 		list.tags = append(list.tags, tag) | ||||||
|  | 	} else if index != -1 { | ||||||
|  | 		list.tags = append(list.tags[0:index], list.tags[index+1:]...) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (list *RoomList) AddToTag(tag string, room *rooms.Room) { | ||||||
|  | 	items, ok := list.items[tag] | ||||||
|  | 	if !ok { | ||||||
|  | 		list.items[tag] = []*rooms.Room{room} | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Add space for new item. | ||||||
|  | 	items = append(items, nil) | ||||||
|  | 	// The default insert index is the newly added slot. | ||||||
|  | 	// That index will be used if all other rooms in the list have the same LastReceivedMessage timestamp. | ||||||
|  | 	insertAt := len(items) - 1 | ||||||
|  | 	// Find the spot where the new room should be put according to the last received message timestamps. | ||||||
|  | 	for i := 0; i < len(items)-1; i++ { | ||||||
|  | 		if items[i].LastReceivedMessage.After(room.LastReceivedMessage) { | ||||||
| 			insertAt = i | 			insertAt = i | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	for i := len(list.items) - 1; i > insertAt; i-- { | 	// Move newer rooms forward in the array. | ||||||
| 		list.items[i] = list.items[i-1] | 	for i := len(items) - 1; i > insertAt; i-- { | ||||||
|  | 		items[i] = items[i-1] | ||||||
| 	} | 	} | ||||||
| 	list.items[insertAt] = room | 	// Insert room. | ||||||
|  | 	items[insertAt] = room | ||||||
|  |  | ||||||
|  | 	list.items[tag] = items | ||||||
|  | 	list.CheckTag(tag) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) Remove(room *rooms.Room) { | func (list *RoomList) Remove(room *rooms.Room) { | ||||||
| 	index := list.Index(room) | 	for _, tag := range room.Tags() { | ||||||
| 	if index != -1 { | 		list.RemoveFromTag(tag.Tag, room) | ||||||
| 		list.items = append(list.items[0:index], list.items[index+1:]...) | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (list *RoomList) RemoveFromTag(tag string, room *rooms.Room) { | ||||||
|  | 	items, ok := list.items[tag] | ||||||
|  | 	if !ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	index := list.indexInTag(tag, room) | ||||||
|  | 	if index == -1 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	items = append(items[0:index], items[index+1:]...) | ||||||
|  |  | ||||||
|  | 	if len(items) == 0 { | ||||||
|  | 		delete(list.items, tag) | ||||||
|  | 	} else { | ||||||
|  | 		list.items[tag] = items | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if room == list.selected { | 	if room == list.selected { | ||||||
|  | 		// Room is currently selected, move selection to another room. | ||||||
| 		if index > 0 { | 		if index > 0 { | ||||||
| 				list.selected = list.items[index-1] | 			list.selected = items[index-1] | ||||||
|  | 		} else if len(items) > 0 { | ||||||
|  | 			list.selected = items[0] | ||||||
| 		} else if len(list.items) > 0 { | 		} else if len(list.items) > 0 { | ||||||
| 				list.selected = list.items[0] | 			for _, tag := range list.tags { | ||||||
|  | 				moreItems := list.items[tag] | ||||||
|  | 				if len(moreItems) > 0 { | ||||||
|  | 					list.selected = moreItems[0] | ||||||
|  | 					list.selectedTag = tag | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			list.selected = nil | 			list.selected = nil | ||||||
|  | 			list.selectedTag = "" | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	} | 	list.CheckTag(tag) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) Bump(room *rooms.Room) { | func (list *RoomList) Bump(room *rooms.Room) { | ||||||
|  | 	for _, tag := range room.Tags() { | ||||||
|  | 		list.bumpInTag(tag.Tag, room) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (list *RoomList) bumpInTag(tag string, room *rooms.Room) { | ||||||
|  | 	items, ok := list.items[tag] | ||||||
|  | 	if !ok { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	found := false | 	found := false | ||||||
| 	for i := 0; i < len(list.items)-1; i++ { | 	for i := 0; i < len(items)-1; i++ { | ||||||
| 		if list.items[i] == room { | 		if items[i] == room { | ||||||
| 			found = true | 			found = true | ||||||
| 		} | 		} | ||||||
| 		if found { | 		if found { | ||||||
| 			list.items[i] = list.items[i+1] | 			items[i] = items[i+1] | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	list.items[len(list.items)-1] = room | 	if found { | ||||||
|  | 		items[len(items)-1] = room | ||||||
| 		room.LastReceivedMessage = time.Now() | 		room.LastReceivedMessage = time.Now() | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) Clear() { | func (list *RoomList) Clear() { | ||||||
| 	list.items = []*rooms.Room{} | 	list.items = make(map[string][]*rooms.Room) | ||||||
| 	list.selected = nil | 	list.selected = nil | ||||||
|  | 	list.selectedTag = "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) SetSelected(room *rooms.Room) { | func (list *RoomList) SetSelected(tag string, room *rooms.Room) { | ||||||
| 	list.selected = room | 	list.selected = room | ||||||
|  | 	list.selectedTag = "" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) HasSelected() bool { | func (list *RoomList) HasSelected() bool { | ||||||
| 	return list.selected != nil | 	return list.selected != nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) Selected() *rooms.Room { | func (list *RoomList) Selected() (string, *rooms.Room) { | ||||||
|  | 	return list.selectedTag, list.selected | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (list *RoomList) SelectedRoom() *rooms.Room { | ||||||
| 	return list.selected | 	return list.selected | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) Previous() *rooms.Room { | func (list *RoomList) First() (string, *rooms.Room) { | ||||||
| 	if len(list.items) == 0 { | 	for _, tag := range list.tags { | ||||||
| 		return nil | 		items := list.items[tag] | ||||||
| 	} else if list.selected == nil { | 		if len(items) > 0 { | ||||||
| 		return list.items[0] | 			return tag, items[0] | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	index := list.Index(list.selected) |  | ||||||
| 	if index == len(list.items)-1 { |  | ||||||
| 		return list.items[0] |  | ||||||
| 	} | 	} | ||||||
| 	return list.items[index+1] | 	return "", nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) Next() *rooms.Room { | func (list *RoomList) Last() (string, *rooms.Room) { | ||||||
|  | 	for tagIndex := len(list.tags) - 1; tagIndex >= 0; tagIndex-- { | ||||||
|  | 		tag := list.tags[tagIndex] | ||||||
|  | 		items := list.items[tag] | ||||||
|  | 		if len(items) > 0 { | ||||||
|  | 			return tag, items[len(items)-1] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return "", nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (list *RoomList) IndexTag(tag string) int { | ||||||
|  | 	for index, entry := range list.tags { | ||||||
|  | 		if tag == entry { | ||||||
|  | 			return index | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return -1 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (list *RoomList) Previous() (string, *rooms.Room) { | ||||||
| 	if len(list.items) == 0 { | 	if len(list.items) == 0 { | ||||||
| 		return nil | 		return "", nil | ||||||
| 	} else if list.selected == nil { | 	} else if list.selected == nil { | ||||||
| 		return list.items[0] | 		return list.First() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	index := list.Index(list.selected) | 	items := list.items[list.selectedTag] | ||||||
|  | 	index := list.indexInTag(list.selectedTag, list.selected) | ||||||
|  | 	if index == len(items)-1 { | ||||||
|  | 		tagIndex := list.IndexTag(list.selectedTag) | ||||||
|  | 		tagIndex++ | ||||||
|  | 		for ; tagIndex < len(list.tags); tagIndex++ { | ||||||
|  | 			nextTag := list.tags[tagIndex] | ||||||
|  | 			nextTagItems := list.items[nextTag] | ||||||
|  | 			if len(nextTagItems) > 0 { | ||||||
|  | 				return nextTag, nextTagItems[0] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return list.First() | ||||||
|  | 	} | ||||||
|  | 	return list.selectedTag, items[index+1] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (list *RoomList) Next() (string, *rooms.Room) { | ||||||
|  | 	if len(list.items) == 0 { | ||||||
|  | 		return "", nil | ||||||
|  | 	} else if list.selected == nil { | ||||||
|  | 		return list.First() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	items := list.items[list.selectedTag] | ||||||
|  | 	index := list.indexInTag(list.selectedTag, list.selected) | ||||||
| 	if index == 0 { | 	if index == 0 { | ||||||
| 		return list.items[len(list.items)-1] | 		tagIndex := list.IndexTag(list.selectedTag) | ||||||
|  | 		tagIndex-- | ||||||
|  | 		for ; tagIndex >= 0; tagIndex-- { | ||||||
|  | 			prevTag := list.tags[tagIndex] | ||||||
|  | 			prevTagItems := list.items[prevTag] | ||||||
|  | 			if len(prevTagItems) > 0 { | ||||||
|  | 				return prevTag, prevTagItems[len(prevTagItems)-1] | ||||||
| 			} | 			} | ||||||
| 	return list.items[index-1] | 		} | ||||||
|  | 		return list.Last() | ||||||
|  | 	} | ||||||
|  | 	return list.selectedTag, items[index-1] | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) Index(room *rooms.Room) int { | func (list *RoomList) indexInTag(tag string, room *rooms.Room) int { | ||||||
| 	roomIndex := -1 | 	roomIndex := -1 | ||||||
| 	for index, entry := range list.items { | 	items := list.items[tag] | ||||||
|  | 	for index, entry := range items { | ||||||
| 		if entry == room { | 		if entry == room { | ||||||
| 			roomIndex = index | 			roomIndex = index | ||||||
| 			break | 			break | ||||||
| @@ -164,11 +315,46 @@ func (list *RoomList) Index(room *rooms.Room) int { | |||||||
| 	return roomIndex | 	return roomIndex | ||||||
| } | } | ||||||
|  |  | ||||||
| func (list *RoomList) Get(n int) *rooms.Room { | func (list *RoomList) Get(n int) (string, *rooms.Room) { | ||||||
| 	if n < 0 || n > len(list.items)-1 { | 	if n < 0 { | ||||||
| 		return nil | 		return "", nil | ||||||
|  | 	} | ||||||
|  | 	for _, tag := range list.tags { | ||||||
|  | 		// Tag header | ||||||
|  | 		n-- | ||||||
|  |  | ||||||
|  | 		items := list.items[tag] | ||||||
|  | 		if n < 0 { | ||||||
|  | 			return "", nil | ||||||
|  | 		} else if n < len(items) { | ||||||
|  | 			return tag, items[len(items)-1-n] | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Tag items | ||||||
|  | 		n -= len(items) | ||||||
|  | 	} | ||||||
|  | 	return "", nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var nsRegex = regexp.MustCompile("^[a-z]\\.[a-z](?:\\.[a-z])*$") | ||||||
|  |  | ||||||
|  | func (list *RoomList) GetTagDisplayName(tag string) string { | ||||||
|  | 	switch { | ||||||
|  | 	case len(tag) == 0: | ||||||
|  | 		return "Rooms" | ||||||
|  | 	case tag == "m.favourite": | ||||||
|  | 		return "Favorites" | ||||||
|  | 	case tag == "m.lowpriority": | ||||||
|  | 		return "Low Priority" | ||||||
|  | 	case strings.HasPrefix(tag, "m."): | ||||||
|  | 		return strings.Title(strings.Replace(tag[len("m."):], "_", " ", -1)) | ||||||
|  | 	case strings.HasPrefix(tag, "u."): | ||||||
|  | 		return tag[len("u."):] | ||||||
|  | 	case !nsRegex.MatchString(tag): | ||||||
|  | 		return tag | ||||||
|  | 	default: | ||||||
|  | 		return "" | ||||||
| 	} | 	} | ||||||
| 	return list.items[len(list.items)-1-n] |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // Draw draws this primitive onto the screen. | // Draw draws this primitive onto the screen. | ||||||
| @@ -179,15 +365,20 @@ func (list *RoomList) Draw(screen tcell.Screen) { | |||||||
| 	bottomLimit := y + height | 	bottomLimit := y + height | ||||||
|  |  | ||||||
| 	var offset int | 	var offset int | ||||||
|  | 	/* TODO fix offset | ||||||
| 	currentItemIndex := list.Index(list.selected) | 	currentItemIndex := list.Index(list.selected) | ||||||
| 	if currentItemIndex >= height { | 	if currentItemIndex >= height { | ||||||
| 		offset = currentItemIndex + 1 - height | 		offset = currentItemIndex + 1 - height | ||||||
| 	} | 	}*/ | ||||||
|  |  | ||||||
| 	// Draw the list items. | 	// Draw the list items. | ||||||
| 	for i := len(list.items) - 1; i >= 0; i-- { | 	for _, tag := range list.tags { | ||||||
| 		item := list.items[i] | 		items := list.items[tag] | ||||||
| 		index := len(list.items) - 1 - i | 		widget.WriteLine(screen, tview.AlignLeft, list.GetTagDisplayName(tag), x, y, width, tcell.StyleDefault.Underline(true).Bold(true)) | ||||||
|  | 		y++ | ||||||
|  | 		for i := len(items) - 1; i >= 0; i-- { | ||||||
|  | 			item := items[i] | ||||||
|  | 			index := len(items) - 1 - i | ||||||
|  |  | ||||||
| 			if index < offset { | 			if index < offset { | ||||||
| 				continue | 				continue | ||||||
| @@ -202,7 +393,7 @@ func (list *RoomList) Draw(screen tcell.Screen) { | |||||||
| 			lineWidth := width | 			lineWidth := width | ||||||
|  |  | ||||||
| 			style := tcell.StyleDefault.Foreground(list.mainTextColor) | 			style := tcell.StyleDefault.Foreground(list.mainTextColor) | ||||||
| 		if item == list.selected { | 			if tag == list.selectedTag && item == list.selected { | ||||||
| 				style = style.Foreground(list.selectedTextColor).Background(list.selectedBackgroundColor) | 				style = style.Foreground(list.selectedTextColor).Background(list.selectedBackgroundColor) | ||||||
| 			} | 			} | ||||||
| 			if item.HasNewMessages { | 			if item.HasNewMessages { | ||||||
| @@ -229,4 +420,5 @@ func (list *RoomList) Draw(screen tcell.Screen) { | |||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -248,7 +248,7 @@ func (view *MainView) MouseEventHandler(roomView *RoomView, event *tcell.EventMo | |||||||
| 	return event | 	return event | ||||||
| } | } | ||||||
|  |  | ||||||
| func (view *MainView) SwitchRoom(room *rooms.Room) { | func (view *MainView) SwitchRoom(tag string, room *rooms.Room) { | ||||||
| 	if room == nil { | 	if room == nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @@ -258,13 +258,13 @@ func (view *MainView) SwitchRoom(room *rooms.Room) { | |||||||
| 	if roomView.MessageView().ScrollOffset == 0 { | 	if roomView.MessageView().ScrollOffset == 0 { | ||||||
| 		roomView.Room.MarkRead() | 		roomView.Room.MarkRead() | ||||||
| 	} | 	} | ||||||
| 	view.roomList.SetSelected(room) | 	view.roomList.SetSelected(tag, room) | ||||||
| 	view.parent.app.SetFocus(view) | 	view.parent.app.SetFocus(view) | ||||||
| 	view.parent.Render() | 	view.parent.Render() | ||||||
| } | } | ||||||
|  |  | ||||||
| func (view *MainView) Focus(delegate func(p tview.Primitive)) { | func (view *MainView) Focus(delegate func(p tview.Primitive)) { | ||||||
| 	room := view.roomList.Selected() | 	room := view.roomList.SelectedRoom() | ||||||
| 	if room != nil { | 	if room != nil { | ||||||
| 		roomView, ok := view.rooms[room.ID] | 		roomView, ok := view.rooms[room.ID] | ||||||
| 		if ok { | 		if ok { | ||||||
| @@ -283,7 +283,6 @@ func (view *MainView) SaveAllHistory() { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (view *MainView) addRoomPage(room *rooms.Room) { | func (view *MainView) addRoomPage(room *rooms.Room) { | ||||||
|  |  | ||||||
| 	if !view.roomView.HasPage(room.ID) { | 	if !view.roomView.HasPage(room.ID) { | ||||||
| 		roomView := NewRoomView(view, room). | 		roomView := NewRoomView(view, room). | ||||||
| 			SetInputSubmitFunc(view.InputSubmit). | 			SetInputSubmitFunc(view.InputSubmit). | ||||||
| @@ -304,7 +303,13 @@ func (view *MainView) addRoomPage(room *rooms.Room) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (view *MainView) GetRoom(roomID string) ifc.RoomView { | func (view *MainView) GetRoom(roomID string) ifc.RoomView { | ||||||
| 	return view.rooms[roomID] | 	room, ok := view.rooms[roomID] | ||||||
|  | 	if !ok { | ||||||
|  | 		view.AddRoom(roomID) | ||||||
|  | 		room, _ := view.rooms[roomID] | ||||||
|  | 		return room | ||||||
|  | 	} | ||||||
|  | 	return room | ||||||
| } | } | ||||||
|  |  | ||||||
| func (view *MainView) AddRoom(roomID string) { | func (view *MainView) AddRoom(roomID string) { | ||||||
| @@ -335,14 +340,46 @@ func (view *MainView) SetRooms(roomIDs []string) { | |||||||
| 	view.roomList.Clear() | 	view.roomList.Clear() | ||||||
| 	view.roomView.Clear() | 	view.roomView.Clear() | ||||||
| 	view.rooms = make(map[string]*RoomView) | 	view.rooms = make(map[string]*RoomView) | ||||||
| 	for index, roomID := range roomIDs { | 	for _, roomID := range roomIDs { | ||||||
| 		room := view.matrix.GetRoom(roomID) | 		room := view.matrix.GetRoom(roomID) | ||||||
| 		view.roomList.Add(room) | 		view.roomList.Add(room) | ||||||
| 		view.addRoomPage(room) | 		view.addRoomPage(room) | ||||||
| 		if index == len(roomIDs)-1 { | 	} | ||||||
| 			view.SwitchRoom(room) | 	view.SwitchRoom(view.roomList.First()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (view *MainView) UpdateTags(room *rooms.Room, newTags []rooms.RoomTag) { | ||||||
|  | 	if len(newTags) == 0 { | ||||||
|  | 		for _, tag := range room.RawTags { | ||||||
|  | 			view.roomList.RemoveFromTag(tag.Tag, room) | ||||||
|  | 		} | ||||||
|  | 		view.roomList.AddToTag("", room) | ||||||
|  | 	} else if len(room.RawTags) == 0 { | ||||||
|  | 		view.roomList.RemoveFromTag("", room) | ||||||
|  | 		for _, tag := range newTags { | ||||||
|  | 			view.roomList.AddToTag(tag.Tag, room) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 	NewTags: | ||||||
|  | 		for _, newTag := range newTags { | ||||||
|  | 			for _, oldTag := range room.RawTags { | ||||||
|  | 				if newTag.Tag == oldTag.Tag { | ||||||
|  | 					continue NewTags | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 			view.roomList.AddToTag(newTag.Tag, room) | ||||||
|  | 		} | ||||||
|  | 	OldTags: | ||||||
|  | 		for _, oldTag := range room.RawTags { | ||||||
|  | 			for _, newTag := range newTags { | ||||||
|  | 				if newTag.Tag == oldTag.Tag { | ||||||
|  | 					continue OldTags | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			view.roomList.RemoveFromTag(oldTag.Tag, room) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	room.RawTags = newTags | ||||||
| } | } | ||||||
|  |  | ||||||
| func (view *MainView) SetTyping(room string, users []string) { | func (view *MainView) SetTyping(room string, users []string) { | ||||||
| @@ -362,7 +399,7 @@ func sendNotification(room *rooms.Room, sender, text string, critical, sound boo | |||||||
|  |  | ||||||
| func (view *MainView) NotifyMessage(room *rooms.Room, message ifc.Message, should pushrules.PushActionArrayShould) { | func (view *MainView) NotifyMessage(room *rooms.Room, message ifc.Message, should pushrules.PushActionArrayShould) { | ||||||
| 	// Whether or not the room where the message came is the currently shown room. | 	// Whether or not the room where the message came is the currently shown room. | ||||||
| 	isCurrent := room == view.roomList.Selected() | 	isCurrent := room == view.roomList.SelectedRoom() | ||||||
| 	// Whether or not the terminal window is focused. | 	// Whether or not the terminal window is focused. | ||||||
| 	isFocused := view.lastFocusTime.Add(30 * time.Second).Before(time.Now()) | 	isFocused := view.lastFocusTime.Add(30 * time.Second).Before(time.Now()) | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user