Move TagRoomList stuff into new file and split RoomList.Draw()
This commit is contained in:
parent
c87097627e
commit
f5e07f40db
450
ui/room-list.go
450
ui/room-list.go
@ -17,210 +17,23 @@
|
|||||||
package ui
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"math"
|
"math"
|
||||||
"maunium.net/go/gomuks/debug"
|
"maunium.net/go/gomuks/debug"
|
||||||
"maunium.net/go/gomuks/matrix/rooms"
|
"maunium.net/go/gomuks/matrix/rooms"
|
||||||
"maunium.net/go/gomuks/ui/widget"
|
|
||||||
"maunium.net/go/tcell"
|
"maunium.net/go/tcell"
|
||||||
"maunium.net/go/tview"
|
"maunium.net/go/tview"
|
||||||
)
|
)
|
||||||
|
|
||||||
type orderedRoom struct {
|
|
||||||
*rooms.Room
|
|
||||||
order string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newOrderedRoom(order string, room *rooms.Room) *orderedRoom {
|
|
||||||
return &orderedRoom{
|
|
||||||
Room: room,
|
|
||||||
order: order,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertRoom(room *rooms.Room) *orderedRoom {
|
|
||||||
return newOrderedRoom("0.5", room)
|
|
||||||
}
|
|
||||||
|
|
||||||
type tagRoomList struct {
|
|
||||||
rooms []*orderedRoom
|
|
||||||
maxShown int
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTagRoomList(rooms ...*orderedRoom) *tagRoomList {
|
|
||||||
return &tagRoomList{
|
|
||||||
maxShown: 10,
|
|
||||||
rooms: rooms,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) Visible() []*orderedRoom {
|
|
||||||
return trl.rooms[len(trl.rooms)-trl.Length():]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) FirstVisible() *rooms.Room {
|
|
||||||
visible := trl.Visible()
|
|
||||||
if len(visible) > 0 {
|
|
||||||
return visible[len(visible)-1].Room
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) LastVisible() *rooms.Room {
|
|
||||||
visible := trl.Visible()
|
|
||||||
if len(visible) > 0 {
|
|
||||||
return visible[0].Room
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) All() []*orderedRoom {
|
|
||||||
return trl.rooms
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) Length() int {
|
|
||||||
if len(trl.rooms) < trl.maxShown {
|
|
||||||
return len(trl.rooms)
|
|
||||||
}
|
|
||||||
return trl.maxShown
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) TotalLength() int {
|
|
||||||
return len(trl.rooms)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) IsEmpty() bool {
|
|
||||||
return len(trl.rooms) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) IsCollapsed() bool {
|
|
||||||
return trl.maxShown == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) ToggleCollapse() {
|
|
||||||
if trl.IsCollapsed() {
|
|
||||||
trl.maxShown = 10
|
|
||||||
} else {
|
|
||||||
trl.maxShown = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) HasInvisibleRooms() bool {
|
|
||||||
return trl.maxShown < trl.TotalLength()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) HasVisibleRooms() bool {
|
|
||||||
return !trl.IsEmpty() && trl.maxShown > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// ShouldBeBefore returns if the first room should be after the second room in the room list.
|
|
||||||
// The manual order and last received message timestamp are considered.
|
|
||||||
func (trl *tagRoomList) ShouldBeAfter(room1 *orderedRoom, room2 *orderedRoom) bool {
|
|
||||||
orderComp := strings.Compare(room1.order, room2.order)
|
|
||||||
return orderComp == 1 || (orderComp == 0 && room2.LastReceivedMessage.After(room1.LastReceivedMessage))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) Insert(order string, mxRoom *rooms.Room) {
|
|
||||||
room := newOrderedRoom(order, mxRoom)
|
|
||||||
trl.rooms = append(trl.rooms, 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(trl.rooms) - 1
|
|
||||||
// Find the spot where the new room should be put according to the last received message timestamps.
|
|
||||||
for i := 0; i < len(trl.rooms)-1; i++ {
|
|
||||||
if trl.ShouldBeAfter(room, trl.rooms[i]) {
|
|
||||||
insertAt = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Move newer rooms forward in the array.
|
|
||||||
for i := len(trl.rooms) - 1; i > insertAt; i-- {
|
|
||||||
trl.rooms[i] = trl.rooms[i-1]
|
|
||||||
}
|
|
||||||
// Insert room.
|
|
||||||
trl.rooms[insertAt] = room
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) String() string {
|
|
||||||
var str strings.Builder
|
|
||||||
fmt.Fprintln(&str, "&tagRoomList{")
|
|
||||||
fmt.Fprintf(&str, " maxShown: %d,\n", trl.maxShown)
|
|
||||||
fmt.Fprint(&str, " rooms: {")
|
|
||||||
for i, room := range trl.rooms {
|
|
||||||
if room == nil {
|
|
||||||
fmt.Fprintf(&str, "<<NIL>>")
|
|
||||||
} else {
|
|
||||||
fmt.Fprint(&str, room.ID)
|
|
||||||
}
|
|
||||||
if i != len(trl.rooms)-1 {
|
|
||||||
fmt.Fprint(&str, ", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Fprintln(&str, "},")
|
|
||||||
fmt.Fprintln(&str, "}")
|
|
||||||
return str.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) Bump(mxRoom *rooms.Room) {
|
|
||||||
var found *orderedRoom
|
|
||||||
for i := 0; i < len(trl.rooms); i++ {
|
|
||||||
currentRoom := trl.rooms[i]
|
|
||||||
if found != nil {
|
|
||||||
if trl.ShouldBeAfter(found, trl.rooms[i]) {
|
|
||||||
// This room should be after the room being bumped, so insert the
|
|
||||||
// room being bumped here and return
|
|
||||||
trl.rooms[i-1] = found
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Move older rooms back in the array
|
|
||||||
trl.rooms[i-1] = currentRoom
|
|
||||||
} else if currentRoom.Room == mxRoom {
|
|
||||||
found = currentRoom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the room being bumped should be first in the list, it won't be inserted during the loop.
|
|
||||||
trl.rooms[len(trl.rooms)-1] = found
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) Remove(room *rooms.Room) {
|
|
||||||
trl.RemoveIndex(trl.Index(room))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) RemoveIndex(index int) {
|
|
||||||
if index < 0 || index > len(trl.rooms) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
trl.rooms = append(trl.rooms[0:index], trl.rooms[index+1:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) Index(room *rooms.Room) int {
|
|
||||||
return trl.indexInList(trl.All(), room)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) IndexVisible(room *rooms.Room) int {
|
|
||||||
return trl.indexInList(trl.Visible(), room)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trl *tagRoomList) indexInList(list []*orderedRoom, room *rooms.Room) int {
|
|
||||||
for index, entry := range list {
|
|
||||||
if entry.Room == room {
|
|
||||||
return index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
type RoomList struct {
|
type RoomList struct {
|
||||||
*tview.Box
|
*tview.Box
|
||||||
|
|
||||||
// The list of tags in display order.
|
// The list of tags in display order.
|
||||||
tags []string
|
tags []string
|
||||||
// The list of rooms, in reverse order.
|
// The list of rooms, in reverse order.
|
||||||
items map[string]*tagRoomList
|
items map[string]*TagRoomList
|
||||||
// The selected room.
|
// The selected room.
|
||||||
selected *rooms.Room
|
selected *rooms.Room
|
||||||
selectedTag string
|
selectedTag string
|
||||||
@ -238,7 +51,7 @@ type RoomList struct {
|
|||||||
func NewRoomList() *RoomList {
|
func NewRoomList() *RoomList {
|
||||||
list := &RoomList{
|
list := &RoomList{
|
||||||
Box: tview.NewBox(),
|
Box: tview.NewBox(),
|
||||||
items: make(map[string]*tagRoomList),
|
items: make(map[string]*TagRoomList),
|
||||||
tags: []string{"m.favourite", "net.maunium.gomuks.fake.direct", "", "m.lowpriority"},
|
tags: []string{"m.favourite", "net.maunium.gomuks.fake.direct", "", "m.lowpriority"},
|
||||||
|
|
||||||
scrollOffset: 0,
|
scrollOffset: 0,
|
||||||
@ -248,14 +61,14 @@ func NewRoomList() *RoomList {
|
|||||||
selectedBackgroundColor: tcell.ColorDarkGreen,
|
selectedBackgroundColor: tcell.ColorDarkGreen,
|
||||||
}
|
}
|
||||||
for _, tag := range list.tags {
|
for _, tag := range list.tags {
|
||||||
list.items[tag] = newTagRoomList()
|
list.items[tag] = NewTagRoomList(list, tag)
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *RoomList) Contains(roomID string) bool {
|
func (list *RoomList) Contains(roomID string) bool {
|
||||||
for _, tagRoomList := range list.items {
|
for _, trl := range list.items {
|
||||||
for _, room := range tagRoomList.All() {
|
for _, room := range trl.All() {
|
||||||
if room.ID == roomID {
|
if room.ID == roomID {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -274,9 +87,9 @@ func (list *RoomList) Add(room *rooms.Room) {
|
|||||||
func (list *RoomList) CheckTag(tag string) {
|
func (list *RoomList) CheckTag(tag string) {
|
||||||
index := list.IndexTag(tag)
|
index := list.IndexTag(tag)
|
||||||
|
|
||||||
tagRoomList, ok := list.items[tag]
|
trl, ok := list.items[tag]
|
||||||
|
|
||||||
if ok && tagRoomList.IsEmpty() {
|
if ok && trl.IsEmpty() {
|
||||||
//delete(list.items, tag)
|
//delete(list.items, tag)
|
||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
@ -290,13 +103,13 @@ func (list *RoomList) CheckTag(tag string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (list *RoomList) AddToTag(tag rooms.RoomTag, room *rooms.Room) {
|
func (list *RoomList) AddToTag(tag rooms.RoomTag, room *rooms.Room) {
|
||||||
tagRoomList, ok := list.items[tag.Tag]
|
trl, ok := list.items[tag.Tag]
|
||||||
if !ok {
|
if !ok {
|
||||||
list.items[tag.Tag] = newTagRoomList(convertRoom(room))
|
list.items[tag.Tag] = NewTagRoomList(list, tag.Tag, convertRoom(room))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tagRoomList.Insert(tag.Order, room)
|
trl.Insert(tag.Order, room)
|
||||||
list.CheckTag(tag.Tag)
|
list.CheckTag(tag.Tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,27 +120,27 @@ func (list *RoomList) Remove(room *rooms.Room) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (list *RoomList) RemoveFromTag(tag string, room *rooms.Room) {
|
func (list *RoomList) RemoveFromTag(tag string, room *rooms.Room) {
|
||||||
tagRoomList, ok := list.items[tag]
|
trl, ok := list.items[tag]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
index := tagRoomList.Index(room)
|
index := trl.Index(room)
|
||||||
if index == -1 {
|
if index == -1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tagRoomList.RemoveIndex(index)
|
trl.RemoveIndex(index)
|
||||||
|
|
||||||
if tagRoomList.IsEmpty() {
|
if trl.IsEmpty() {
|
||||||
// delete(list.items, tag)
|
// delete(list.items, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
if room == list.selected {
|
if room == list.selected {
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
list.selected = tagRoomList.All()[index-1].Room
|
list.selected = trl.All()[index-1].Room
|
||||||
} else if tagRoomList.Length() > 0 {
|
} else if trl.Length() > 0 {
|
||||||
list.selected = tagRoomList.Visible()[0].Room
|
list.selected = trl.Visible()[0].Room
|
||||||
} else if len(list.items) > 0 {
|
} else if len(list.items) > 0 {
|
||||||
for _, tag := range list.tags {
|
for _, tag := range list.tags {
|
||||||
moreItems := list.items[tag]
|
moreItems := list.items[tag]
|
||||||
@ -346,19 +159,19 @@ func (list *RoomList) RemoveFromTag(tag string, room *rooms.Room) {
|
|||||||
|
|
||||||
func (list *RoomList) Bump(room *rooms.Room) {
|
func (list *RoomList) Bump(room *rooms.Room) {
|
||||||
for _, tag := range room.Tags() {
|
for _, tag := range room.Tags() {
|
||||||
tagRoomList, ok := list.items[tag.Tag]
|
trl, ok := list.items[tag.Tag]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tagRoomList.Bump(room)
|
trl.Bump(room)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (list *RoomList) Clear() {
|
func (list *RoomList) Clear() {
|
||||||
list.items = make(map[string]*tagRoomList)
|
list.items = make(map[string]*TagRoomList)
|
||||||
list.tags = []string{"m.favourite", "net.maunium.gomuks.fake.direct", "", "m.lowpriority"}
|
list.tags = []string{"m.favourite", "net.maunium.gomuks.fake.direct", "", "m.lowpriority"}
|
||||||
for _, tag := range list.tags {
|
for _, tag := range list.tags {
|
||||||
list.items[tag] = newTagRoomList()
|
list.items[tag] = NewTagRoomList(list, tag)
|
||||||
}
|
}
|
||||||
list.selected = nil
|
list.selected = nil
|
||||||
list.selectedTag = ""
|
list.selectedTag = ""
|
||||||
@ -406,9 +219,9 @@ func (list *RoomList) AddScrollOffset(offset int) {
|
|||||||
|
|
||||||
func (list *RoomList) First() (string, *rooms.Room) {
|
func (list *RoomList) First() (string, *rooms.Room) {
|
||||||
for _, tag := range list.tags {
|
for _, tag := range list.tags {
|
||||||
tagRoomList := list.items[tag]
|
trl := list.items[tag]
|
||||||
if tagRoomList.HasVisibleRooms() {
|
if trl.HasVisibleRooms() {
|
||||||
return tag, tagRoomList.FirstVisible()
|
return tag, trl.FirstVisible()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
@ -417,9 +230,9 @@ func (list *RoomList) First() (string, *rooms.Room) {
|
|||||||
func (list *RoomList) Last() (string, *rooms.Room) {
|
func (list *RoomList) Last() (string, *rooms.Room) {
|
||||||
for tagIndex := len(list.tags) - 1; tagIndex >= 0; tagIndex-- {
|
for tagIndex := len(list.tags) - 1; tagIndex >= 0; tagIndex-- {
|
||||||
tag := list.tags[tagIndex]
|
tag := list.tags[tagIndex]
|
||||||
tagRoomList := list.items[tag]
|
trl := list.items[tag]
|
||||||
if tagRoomList.HasVisibleRooms() {
|
if trl.HasVisibleRooms() {
|
||||||
return tag, tagRoomList.LastVisible()
|
return tag, trl.LastVisible()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
@ -441,28 +254,28 @@ func (list *RoomList) Previous() (string, *rooms.Room) {
|
|||||||
return list.First()
|
return list.First()
|
||||||
}
|
}
|
||||||
|
|
||||||
tagRoomList := list.items[list.selectedTag]
|
trl := list.items[list.selectedTag]
|
||||||
index := tagRoomList.IndexVisible(list.selected)
|
index := trl.IndexVisible(list.selected)
|
||||||
indexInvisible := tagRoomList.Index(list.selected)
|
indexInvisible := trl.Index(list.selected)
|
||||||
if index == -1 && indexInvisible >= 0 {
|
if index == -1 && indexInvisible >= 0 {
|
||||||
num := tagRoomList.TotalLength() - indexInvisible
|
num := trl.TotalLength() - indexInvisible
|
||||||
tagRoomList.maxShown = int(math.Ceil(float64(num)/10.0) * 10.0)
|
trl.maxShown = int(math.Ceil(float64(num)/10.0) * 10.0)
|
||||||
index = tagRoomList.IndexVisible(list.selected)
|
index = trl.IndexVisible(list.selected)
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == tagRoomList.Length()-1 {
|
if index == trl.Length()-1 {
|
||||||
tagIndex := list.IndexTag(list.selectedTag)
|
tagIndex := list.IndexTag(list.selectedTag)
|
||||||
tagIndex--
|
tagIndex--
|
||||||
for ; tagIndex >= 0; tagIndex-- {
|
for ; tagIndex >= 0; tagIndex-- {
|
||||||
prevTag := list.tags[tagIndex]
|
prevTag := list.tags[tagIndex]
|
||||||
prevTagRoomList := list.items[prevTag]
|
prevTRL := list.items[prevTag]
|
||||||
if prevTagRoomList.HasVisibleRooms() {
|
if prevTRL.HasVisibleRooms() {
|
||||||
return prevTag, prevTagRoomList.LastVisible()
|
return prevTag, prevTRL.LastVisible()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list.Last()
|
return list.Last()
|
||||||
} else if index >= 0 {
|
} else if index >= 0 {
|
||||||
return list.selectedTag, tagRoomList.Visible()[index+1].Room
|
return list.selectedTag, trl.Visible()[index+1].Room
|
||||||
}
|
}
|
||||||
return list.First()
|
return list.First()
|
||||||
}
|
}
|
||||||
@ -474,13 +287,13 @@ func (list *RoomList) Next() (string, *rooms.Room) {
|
|||||||
return list.First()
|
return list.First()
|
||||||
}
|
}
|
||||||
|
|
||||||
tagRoomList := list.items[list.selectedTag]
|
trl := list.items[list.selectedTag]
|
||||||
index := tagRoomList.IndexVisible(list.selected)
|
index := trl.IndexVisible(list.selected)
|
||||||
indexInvisible := tagRoomList.Index(list.selected)
|
indexInvisible := trl.Index(list.selected)
|
||||||
if index == -1 && indexInvisible >= 0 {
|
if index == -1 && indexInvisible >= 0 {
|
||||||
num := tagRoomList.TotalLength() - indexInvisible + 1
|
num := trl.TotalLength() - indexInvisible + 1
|
||||||
tagRoomList.maxShown = int(math.Ceil(float64(num)/10.0) * 10.0)
|
trl.maxShown = int(math.Ceil(float64(num)/10.0) * 10.0)
|
||||||
index = tagRoomList.IndexVisible(list.selected)
|
index = trl.IndexVisible(list.selected)
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
@ -488,14 +301,14 @@ func (list *RoomList) Next() (string, *rooms.Room) {
|
|||||||
tagIndex++
|
tagIndex++
|
||||||
for ; tagIndex < len(list.tags); tagIndex++ {
|
for ; tagIndex < len(list.tags); tagIndex++ {
|
||||||
nextTag := list.tags[tagIndex]
|
nextTag := list.tags[tagIndex]
|
||||||
nextTagRoomList := list.items[nextTag]
|
nextTRL := list.items[nextTag]
|
||||||
if nextTagRoomList.HasVisibleRooms() {
|
if nextTRL.HasVisibleRooms() {
|
||||||
return nextTag, nextTagRoomList.FirstVisible()
|
return nextTag, nextTRL.FirstVisible()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list.First()
|
return list.First()
|
||||||
} else if index > 0 {
|
} else if index > 0 {
|
||||||
return list.selectedTag, tagRoomList.Visible()[index-1].Room
|
return list.selectedTag, trl.Visible()[index-1].Room
|
||||||
}
|
}
|
||||||
return list.Last()
|
return list.Last()
|
||||||
}
|
}
|
||||||
@ -506,39 +319,24 @@ func (list *RoomList) index(tag string, room *rooms.Room) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
tagRoomList, ok := list.items[tag]
|
trl, ok := list.items[tag]
|
||||||
localIndex := -1
|
localIndex := -1
|
||||||
if ok {
|
if ok {
|
||||||
localIndex = tagRoomList.IndexVisible(room)
|
localIndex = trl.IndexVisible(room)
|
||||||
}
|
}
|
||||||
if localIndex == -1 {
|
if localIndex == -1 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
localIndex = tagRoomList.Length() - 1 - localIndex
|
localIndex = trl.Length() - 1 - localIndex
|
||||||
|
|
||||||
// Tag header
|
// Tag header
|
||||||
localIndex += 1
|
localIndex += 1
|
||||||
|
|
||||||
if tagIndex > 0 {
|
if tagIndex > 0 {
|
||||||
for i := 0; i < tagIndex; i++ {
|
for i := 0; i < tagIndex; i++ {
|
||||||
previousTag := list.tags[i]
|
prevTag := list.tags[i]
|
||||||
previousTagRoomList := list.items[previousTag]
|
prevTRL := list.items[prevTag]
|
||||||
|
localIndex += prevTRL.RenderHeight()
|
||||||
tagDisplayName := list.GetTagDisplayName(previousTag)
|
|
||||||
if len(tagDisplayName) > 0 {
|
|
||||||
if previousTagRoomList.IsCollapsed() {
|
|
||||||
localIndex++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Previous tag header + space
|
|
||||||
localIndex += 2
|
|
||||||
if previousTagRoomList.HasInvisibleRooms() {
|
|
||||||
// Previous tag "Show more" button
|
|
||||||
localIndex++
|
|
||||||
}
|
|
||||||
// Previous tag items
|
|
||||||
localIndex += previousTagRoomList.Length()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,19 +345,7 @@ func (list *RoomList) index(tag string, room *rooms.Room) int {
|
|||||||
|
|
||||||
func (list *RoomList) ContentHeight() (height int) {
|
func (list *RoomList) ContentHeight() (height int) {
|
||||||
for _, tag := range list.tags {
|
for _, tag := range list.tags {
|
||||||
tagRoomList := list.items[tag]
|
height += list.items[tag].RenderHeight()
|
||||||
tagDisplayName := list.GetTagDisplayName(tag)
|
|
||||||
if len(tagDisplayName) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if tagRoomList.IsCollapsed() {
|
|
||||||
height++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
height += 2 + tagRoomList.Length()
|
|
||||||
if tagRoomList.HasInvisibleRooms() {
|
|
||||||
height++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -570,27 +356,27 @@ func (list *RoomList) HandleClick(column, line int, mod bool) (string, *rooms.Ro
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
for _, tag := range list.tags {
|
for _, tag := range list.tags {
|
||||||
tagRoomList := list.items[tag]
|
trl := list.items[tag]
|
||||||
if line--; line == -1 {
|
if line--; line == -1 {
|
||||||
tagRoomList.ToggleCollapse()
|
trl.ToggleCollapse()
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if tagRoomList.IsCollapsed() {
|
if trl.IsCollapsed() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if line < 0 {
|
if line < 0 {
|
||||||
return "", nil
|
return "", nil
|
||||||
} else if line < tagRoomList.Length() {
|
} else if line < trl.Length() {
|
||||||
return tag, tagRoomList.Visible()[tagRoomList.Length()-1-line].Room
|
return tag, trl.Visible()[trl.Length()-1-line].Room
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tag items
|
// Tag items
|
||||||
line -= tagRoomList.Length()
|
line -= trl.Length()
|
||||||
|
|
||||||
hasMore := tagRoomList.HasInvisibleRooms()
|
hasMore := trl.HasInvisibleRooms()
|
||||||
hasLess := tagRoomList.maxShown > 10
|
hasLess := trl.maxShown > 10
|
||||||
if hasMore || hasLess {
|
if hasMore || hasLess {
|
||||||
if line--; line == -1 {
|
if line--; line == -1 {
|
||||||
diff := 10
|
diff := 10
|
||||||
@ -599,12 +385,12 @@ func (list *RoomList) HandleClick(column, line int, mod bool) (string, *rooms.Ro
|
|||||||
}
|
}
|
||||||
_, _, width, _ := list.GetRect()
|
_, _, width, _ := list.GetRect()
|
||||||
if column <= 6 && hasLess {
|
if column <= 6 && hasLess {
|
||||||
tagRoomList.maxShown -= diff
|
trl.maxShown -= diff
|
||||||
} else if column >= width-6 && hasMore {
|
} else if column >= width-6 && hasMore {
|
||||||
tagRoomList.maxShown += diff
|
trl.maxShown += diff
|
||||||
}
|
}
|
||||||
if tagRoomList.maxShown < 10 {
|
if trl.maxShown < 10 {
|
||||||
tagRoomList.maxShown = 10
|
trl.maxShown = 10
|
||||||
}
|
}
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
@ -641,108 +427,26 @@ func (list *RoomList) Draw(screen tcell.Screen) {
|
|||||||
list.Box.Draw(screen)
|
list.Box.Draw(screen)
|
||||||
|
|
||||||
x, y, width, height := list.GetInnerRect()
|
x, y, width, height := list.GetInnerRect()
|
||||||
bottomLimit := y + height
|
yLimit := y + height
|
||||||
|
y -= list.scrollOffset
|
||||||
handledOffset := 0
|
|
||||||
|
|
||||||
// Draw the list items.
|
// Draw the list items.
|
||||||
for _, tag := range list.tags {
|
for _, tag := range list.tags {
|
||||||
tagRoomList := list.items[tag]
|
trl := list.items[tag]
|
||||||
tagDisplayName := list.GetTagDisplayName(tag)
|
tagDisplayName := list.GetTagDisplayName(tag)
|
||||||
if len(tagDisplayName) == 0 {
|
if len(tagDisplayName) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
localOffset := 0
|
renderHeight := trl.RenderHeight()
|
||||||
|
if y + renderHeight >= yLimit {
|
||||||
if handledOffset < list.scrollOffset {
|
renderHeight = yLimit - y
|
||||||
if handledOffset+tagRoomList.Length() < list.scrollOffset {
|
|
||||||
if tagRoomList.IsCollapsed() {
|
|
||||||
handledOffset++
|
|
||||||
} else {
|
|
||||||
handledOffset += tagRoomList.Length() + 2
|
|
||||||
if tagRoomList.HasInvisibleRooms() || tagRoomList.maxShown > 10 {
|
|
||||||
handledOffset++
|
|
||||||
}
|
}
|
||||||
}
|
trl.SetRect(x, y, width, renderHeight)
|
||||||
continue
|
trl.Draw(screen)
|
||||||
} else {
|
y += renderHeight
|
||||||
localOffset = list.scrollOffset - handledOffset
|
if y >= yLimit {
|
||||||
handledOffset += localOffset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
roomCount := strconv.Itoa(tagRoomList.TotalLength())
|
|
||||||
widget.WriteLine(screen, tview.AlignLeft, tagDisplayName, x, y, width-1-len(roomCount), tcell.StyleDefault.Underline(true).Bold(true))
|
|
||||||
widget.WriteLine(screen, tview.AlignLeft, roomCount, x+len(tagDisplayName)+1, y, width-2-len(tagDisplayName), tcell.StyleDefault.Italic(true))
|
|
||||||
|
|
||||||
items := tagRoomList.Visible()
|
|
||||||
|
|
||||||
if tagRoomList.IsCollapsed() {
|
|
||||||
screen.SetCell(x+width-1, y, tcell.StyleDefault, '▶')
|
|
||||||
y++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
screen.SetCell(x+width-1, y, tcell.StyleDefault, '▼')
|
|
||||||
y++
|
|
||||||
|
|
||||||
for i := tagRoomList.Length() - 1; i >= 0; i-- {
|
|
||||||
item := items[i]
|
|
||||||
index := len(items) - 1 - i
|
|
||||||
|
|
||||||
if y >= bottomLimit {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if index < localOffset {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
text := item.GetTitle()
|
|
||||||
|
|
||||||
lineWidth := width
|
|
||||||
|
|
||||||
style := tcell.StyleDefault.Foreground(list.mainTextColor)
|
|
||||||
if tag == list.selectedTag && item.Room == list.selected {
|
|
||||||
style = style.Foreground(list.selectedTextColor).Background(list.selectedBackgroundColor)
|
|
||||||
}
|
|
||||||
if item.HasNewMessages() {
|
|
||||||
style = style.Bold(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
unreadCount := item.UnreadCount()
|
|
||||||
if unreadCount > 0 {
|
|
||||||
unreadMessageCount := "99+"
|
|
||||||
if unreadCount < 100 {
|
|
||||||
unreadMessageCount = strconv.Itoa(unreadCount)
|
|
||||||
}
|
|
||||||
if item.Highlighted() {
|
|
||||||
unreadMessageCount += "!"
|
|
||||||
}
|
|
||||||
unreadMessageCount = fmt.Sprintf("(%s)", unreadMessageCount)
|
|
||||||
widget.WriteLine(screen, tview.AlignRight, unreadMessageCount, x+lineWidth-7, y, 7, style)
|
|
||||||
lineWidth -= len(unreadMessageCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
widget.WriteLinePadded(screen, tview.AlignLeft, text, x, y, lineWidth, style)
|
|
||||||
y++
|
|
||||||
|
|
||||||
if y >= bottomLimit {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hasLess := tagRoomList.maxShown > 10
|
|
||||||
hasMore := tagRoomList.HasInvisibleRooms()
|
|
||||||
if hasLess || hasMore {
|
|
||||||
if hasMore {
|
|
||||||
widget.WriteLine(screen, tview.AlignRight, "More ↓", x, y, width, tcell.StyleDefault)
|
|
||||||
}
|
|
||||||
if hasLess {
|
|
||||||
widget.WriteLine(screen, tview.AlignLeft, "↑ Less", x, y, width, tcell.StyleDefault)
|
|
||||||
}
|
|
||||||
y++
|
|
||||||
}
|
|
||||||
|
|
||||||
y++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
314
ui/tag-room-list.go
Normal file
314
ui/tag-room-list.go
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
// gomuks - A terminal Matrix client written in Go.
|
||||||
|
// Copyright (C) 2018 Tulir Asokan
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package ui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"maunium.net/go/gomuks/matrix/rooms"
|
||||||
|
"strings"
|
||||||
|
"fmt"
|
||||||
|
"maunium.net/go/tcell"
|
||||||
|
"strconv"
|
||||||
|
"maunium.net/go/gomuks/ui/widget"
|
||||||
|
"maunium.net/go/tview"
|
||||||
|
)
|
||||||
|
|
||||||
|
type orderedRoom struct {
|
||||||
|
*rooms.Room
|
||||||
|
order string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOrderedRoom(order string, room *rooms.Room) *orderedRoom {
|
||||||
|
return &orderedRoom{
|
||||||
|
Room: room,
|
||||||
|
order: order,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertRoom(room *rooms.Room) *orderedRoom {
|
||||||
|
return newOrderedRoom("0.5", room)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TagRoomList struct {
|
||||||
|
*tview.Box
|
||||||
|
rooms []*orderedRoom
|
||||||
|
maxShown int
|
||||||
|
name string
|
||||||
|
displayname string
|
||||||
|
parent *RoomList
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTagRoomList(parent *RoomList, name string, rooms ...*orderedRoom) *TagRoomList {
|
||||||
|
return &TagRoomList{
|
||||||
|
Box: tview.NewBox(),
|
||||||
|
maxShown: 10,
|
||||||
|
rooms: rooms,
|
||||||
|
name: name,
|
||||||
|
displayname: parent.GetTagDisplayName(name),
|
||||||
|
parent: parent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) Visible() []*orderedRoom {
|
||||||
|
return trl.rooms[len(trl.rooms)-trl.Length():]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) FirstVisible() *rooms.Room {
|
||||||
|
visible := trl.Visible()
|
||||||
|
if len(visible) > 0 {
|
||||||
|
return visible[len(visible)-1].Room
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) LastVisible() *rooms.Room {
|
||||||
|
visible := trl.Visible()
|
||||||
|
if len(visible) > 0 {
|
||||||
|
return visible[0].Room
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) All() []*orderedRoom {
|
||||||
|
return trl.rooms
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) Length() int {
|
||||||
|
if len(trl.rooms) < trl.maxShown {
|
||||||
|
return len(trl.rooms)
|
||||||
|
}
|
||||||
|
return trl.maxShown
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) TotalLength() int {
|
||||||
|
return len(trl.rooms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) IsEmpty() bool {
|
||||||
|
return len(trl.rooms) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) IsCollapsed() bool {
|
||||||
|
return trl.maxShown == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) ToggleCollapse() {
|
||||||
|
if trl.IsCollapsed() {
|
||||||
|
trl.maxShown = 10
|
||||||
|
} else {
|
||||||
|
trl.maxShown = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) HasInvisibleRooms() bool {
|
||||||
|
return trl.maxShown < trl.TotalLength()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) HasVisibleRooms() bool {
|
||||||
|
return !trl.IsEmpty() && trl.maxShown > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShouldBeBefore returns if the first room should be after the second room in the room list.
|
||||||
|
// The manual order and last received message timestamp are considered.
|
||||||
|
func (trl *TagRoomList) ShouldBeAfter(room1 *orderedRoom, room2 *orderedRoom) bool {
|
||||||
|
orderComp := strings.Compare(room1.order, room2.order)
|
||||||
|
return orderComp == 1 || (orderComp == 0 && room2.LastReceivedMessage.After(room1.LastReceivedMessage))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) Insert(order string, mxRoom *rooms.Room) {
|
||||||
|
room := newOrderedRoom(order, mxRoom)
|
||||||
|
trl.rooms = append(trl.rooms, 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(trl.rooms) - 1
|
||||||
|
// Find the spot where the new room should be put according to the last received message timestamps.
|
||||||
|
for i := 0; i < len(trl.rooms)-1; i++ {
|
||||||
|
if trl.ShouldBeAfter(room, trl.rooms[i]) {
|
||||||
|
insertAt = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Move newer rooms forward in the array.
|
||||||
|
for i := len(trl.rooms) - 1; i > insertAt; i-- {
|
||||||
|
trl.rooms[i] = trl.rooms[i-1]
|
||||||
|
}
|
||||||
|
// Insert room.
|
||||||
|
trl.rooms[insertAt] = room
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) String() string {
|
||||||
|
var str strings.Builder
|
||||||
|
fmt.Fprintln(&str, "&TagRoomList{")
|
||||||
|
fmt.Fprintf(&str, " maxShown: %d,\n", trl.maxShown)
|
||||||
|
fmt.Fprint(&str, " rooms: {")
|
||||||
|
for i, room := range trl.rooms {
|
||||||
|
if room == nil {
|
||||||
|
fmt.Fprintf(&str, "<<NIL>>")
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(&str, room.ID)
|
||||||
|
}
|
||||||
|
if i != len(trl.rooms)-1 {
|
||||||
|
fmt.Fprint(&str, ", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprintln(&str, "},")
|
||||||
|
fmt.Fprintln(&str, "}")
|
||||||
|
return str.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) Bump(mxRoom *rooms.Room) {
|
||||||
|
var found *orderedRoom
|
||||||
|
for i := 0; i < len(trl.rooms); i++ {
|
||||||
|
currentRoom := trl.rooms[i]
|
||||||
|
if found != nil {
|
||||||
|
if trl.ShouldBeAfter(found, trl.rooms[i]) {
|
||||||
|
// This room should be after the room being bumped, so insert the
|
||||||
|
// room being bumped here and return
|
||||||
|
trl.rooms[i-1] = found
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Move older rooms back in the array
|
||||||
|
trl.rooms[i-1] = currentRoom
|
||||||
|
} else if currentRoom.Room == mxRoom {
|
||||||
|
found = currentRoom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the room being bumped should be first in the list, it won't be inserted during the loop.
|
||||||
|
trl.rooms[len(trl.rooms)-1] = found
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) Remove(room *rooms.Room) {
|
||||||
|
trl.RemoveIndex(trl.Index(room))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) RemoveIndex(index int) {
|
||||||
|
if index < 0 || index > len(trl.rooms) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
trl.rooms = append(trl.rooms[0:index], trl.rooms[index+1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) Index(room *rooms.Room) int {
|
||||||
|
return trl.indexInList(trl.All(), room)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) IndexVisible(room *rooms.Room) int {
|
||||||
|
return trl.indexInList(trl.Visible(), room)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) indexInList(list []*orderedRoom, room *rooms.Room) int {
|
||||||
|
for index, entry := range list {
|
||||||
|
if entry.Room == room {
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
var TagDisplayNameStyle = tcell.StyleDefault.Underline(true).Bold(true)
|
||||||
|
var TagRoomCountStyle = tcell.StyleDefault.Italic(true)
|
||||||
|
|
||||||
|
func (trl *TagRoomList) RenderHeight() int {
|
||||||
|
if len(trl.displayname) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if trl.IsCollapsed() {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
height := 2 + trl.Length()
|
||||||
|
if trl.HasInvisibleRooms() || trl.maxShown > 10 {
|
||||||
|
height++
|
||||||
|
}
|
||||||
|
return height
|
||||||
|
}
|
||||||
|
|
||||||
|
func (trl *TagRoomList) Draw(screen tcell.Screen) {
|
||||||
|
if len(trl.displayname) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
x, y, width, height := trl.GetRect()
|
||||||
|
yLimit := y + height
|
||||||
|
|
||||||
|
roomCount := strconv.Itoa(trl.TotalLength())
|
||||||
|
|
||||||
|
// Draw tag name
|
||||||
|
displayNameWidth := width - 1 - len(roomCount)
|
||||||
|
widget.WriteLine(screen, tview.AlignLeft, trl.displayname, x, y, displayNameWidth, TagDisplayNameStyle)
|
||||||
|
|
||||||
|
// Draw tag room count
|
||||||
|
roomCountX := x + len(trl.displayname) + 1
|
||||||
|
roomCountWidth := width - 2 - len(trl.displayname)
|
||||||
|
widget.WriteLine(screen, tview.AlignLeft, roomCount, roomCountX, y, roomCountWidth, TagRoomCountStyle)
|
||||||
|
|
||||||
|
items := trl.Visible()
|
||||||
|
|
||||||
|
if trl.IsCollapsed() {
|
||||||
|
screen.SetCell(x+width-1, y, tcell.StyleDefault, '▶')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
screen.SetCell(x+width-1, y, tcell.StyleDefault, '▼')
|
||||||
|
|
||||||
|
offsetY := 1
|
||||||
|
for i := trl.Length() - 1; i >= 0; i-- {
|
||||||
|
if y+offsetY >= yLimit {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
item := items[i]
|
||||||
|
|
||||||
|
text := item.GetTitle()
|
||||||
|
|
||||||
|
lineWidth := width
|
||||||
|
|
||||||
|
style := tcell.StyleDefault.Foreground(trl.parent.mainTextColor)
|
||||||
|
if trl.name == trl.parent.selectedTag && item.Room == trl.parent.selected {
|
||||||
|
style = style.Foreground(trl.parent.selectedTextColor).Background(trl.parent.selectedBackgroundColor)
|
||||||
|
}
|
||||||
|
if item.HasNewMessages() {
|
||||||
|
style = style.Bold(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
unreadCount := item.UnreadCount()
|
||||||
|
if unreadCount > 0 {
|
||||||
|
unreadMessageCount := "99+"
|
||||||
|
if unreadCount < 100 {
|
||||||
|
unreadMessageCount = strconv.Itoa(unreadCount)
|
||||||
|
}
|
||||||
|
if item.Highlighted() {
|
||||||
|
unreadMessageCount += "!"
|
||||||
|
}
|
||||||
|
unreadMessageCount = fmt.Sprintf("(%s)", unreadMessageCount)
|
||||||
|
widget.WriteLine(screen, tview.AlignRight, unreadMessageCount, x+lineWidth-7, y+offsetY, 7, style)
|
||||||
|
lineWidth -= len(unreadMessageCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.WriteLinePadded(screen, tview.AlignLeft, text, x, y+offsetY, lineWidth, style)
|
||||||
|
offsetY++
|
||||||
|
}
|
||||||
|
hasLess := trl.maxShown > 10
|
||||||
|
hasMore := trl.HasInvisibleRooms()
|
||||||
|
if (hasLess || hasMore) && y+offsetY < yLimit {
|
||||||
|
if hasMore {
|
||||||
|
widget.WriteLine(screen, tview.AlignRight, "More ↓", x, y+offsetY, width, tcell.StyleDefault)
|
||||||
|
}
|
||||||
|
if hasLess {
|
||||||
|
widget.WriteLine(screen, tview.AlignLeft, "↑ Less", x, y+offsetY, width, tcell.StyleDefault)
|
||||||
|
}
|
||||||
|
offsetY++
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user