Organize room list by last received message (ref #11)

This commit is contained in:
Tulir Asokan 2018-04-23 22:49:17 +03:00
parent 16406d6c91
commit 1e8705319a
4 changed files with 139 additions and 98 deletions

View File

@ -49,7 +49,6 @@ type GomuksUI interface {
type MainView interface { type MainView interface {
GetRoom(roomID string) RoomView GetRoom(roomID string) RoomView
HasRoom(roomID string) bool
AddRoom(roomID string) AddRoom(roomID string)
RemoveRoom(roomID string) RemoveRoom(roomID string)
SetRooms(roomIDs []string) SetRooms(roomIDs []string)

View File

@ -17,7 +17,9 @@
package open package open
import ( import (
"os"
"os/exec" "os/exec"
"path/filepath"
) )
const FileProtocolHandler = "url.dll,FileProtocolHandler" const FileProtocolHandler = "url.dll,FileProtocolHandler"

View File

@ -29,7 +29,6 @@ import (
type RoomList struct { type RoomList struct {
*tview.Box *tview.Box
indices map[*rooms.Room]int
items []*rooms.Room items []*rooms.Room
selected *rooms.Room selected *rooms.Room
@ -43,9 +42,8 @@ type RoomList struct {
func NewRoomList() *RoomList { func NewRoomList() *RoomList {
return &RoomList{ return &RoomList{
Box: tview.NewBox(), Box: tview.NewBox(),
indices: make(map[*rooms.Room]int), items: []*rooms.Room{},
items: []*rooms.Room{},
mainTextColor: tcell.ColorWhite, mainTextColor: tcell.ColorWhite,
selectedTextColor: tcell.ColorWhite, selectedTextColor: tcell.ColorWhite,
@ -53,28 +51,49 @@ func NewRoomList() *RoomList {
} }
} }
func (list *RoomList) Add(room *rooms.Room) { func (list *RoomList) Contains(roomID string) bool {
list.indices[room] = len(list.items) for _, room := range list.items {
list.items = append(list.items, room) if room.ID == roomID {
if list.selected == nil { return true
list.selected = room }
} }
return false
}
func (list *RoomList) Add(room *rooms.Room) {
list.items = append(list.items, room)
} }
func (list *RoomList) Remove(room *rooms.Room) { func (list *RoomList) Remove(room *rooms.Room) {
index, ok := list.indices[room] index := list.Index(room)
if !ok { if index != -1 {
return list.items = append(list.items[0:index], list.items[index+1:]...)
} if room == list.selected {
delete(list.indices, room) if index > 0 {
list.items = append(list.items[0:index], list.items[index+1:]...) list.selected = list.items[index-1]
if len(list.items) == 0 { } else if len(list.items) > 0 {
list.selected = nil list.selected = list.items[0]
} else {
list.selected = nil
}
}
} }
} }
func (list *RoomList) Bump(room *rooms.Room) {
found := false
for i := 0; i < len(list.items)-1; i++ {
if list.items[i] == room {
found = true
}
if found {
list.items[i] = list.items[i+1]
}
}
list.items[len(list.items)-1] = room
}
func (list *RoomList) Clear() { func (list *RoomList) Clear() {
list.indices = make(map[*rooms.Room]int)
list.items = []*rooms.Room{} list.items = []*rooms.Room{}
list.selected = nil list.selected = nil
} }
@ -83,11 +102,55 @@ func (list *RoomList) SetSelected(room *rooms.Room) {
list.selected = room list.selected = room
} }
func (list *RoomList) Get(n int) *rooms.Room { func (list *RoomList) HasSelected() bool {
if n < 0 || n >= len(list.items) { return list.selected != nil
}
func (list *RoomList) Selected() *rooms.Room {
return list.selected
}
func (list *RoomList) Previous() *rooms.Room {
if len(list.items) == 0 {
return nil return nil
} else if list.selected == nil {
return list.items[0]
} }
return list.items[n]
index := list.Index(list.selected)
if index == len(list.items)-1 {
return list.items[0]
}
return list.items[index+1]
}
func (list *RoomList) Next() *rooms.Room {
if len(list.items) == 0 {
return nil
} else if list.selected == nil {
return list.items[0]
}
index := list.Index(list.selected)
if index == 0 {
return list.items[len(list.items)-1]
}
return list.items[index-1]
}
func (list *RoomList) Index(room *rooms.Room) int {
roomIndex := -1
for index, entry := range list.items {
if entry == room {
roomIndex = index
break
}
}
return roomIndex
}
func (list *RoomList) Get(n int) *rooms.Room {
return list.items[len(list.items)-1-(n%len(list.items))]
} }
// Draw draws this primitive onto the screen. // Draw draws this primitive onto the screen.
@ -98,13 +161,16 @@ func (list *RoomList) Draw(screen tcell.Screen) {
bottomLimit := y + height bottomLimit := y + height
var offset int var offset int
currentItemIndex, hasSelected := list.indices[list.selected] currentItemIndex := list.Index(list.selected)
if hasSelected && currentItemIndex >= height { if currentItemIndex >= height {
offset = currentItemIndex + 1 - height offset = currentItemIndex + 1 - height
} }
// Draw the list items. // Draw the list items.
for index, item := range list.items { for i := len(list.items) - 1; i >= 0; i-- {
item := list.items[i]
index := len(list.items) - 1 - i
if index < offset { if index < offset {
continue continue
} }

View File

@ -18,7 +18,6 @@ package ui
import ( import (
"fmt" "fmt"
"sort"
"strings" "strings"
"time" "time"
"unicode" "unicode"
@ -39,11 +38,9 @@ import (
type MainView struct { type MainView struct {
*tview.Flex *tview.Flex
roomList *RoomList roomList *RoomList
roomView *tview.Pages roomView *tview.Pages
rooms map[string]*RoomView rooms map[string]*RoomView
currentRoomIndex int
roomIDs []string
lastFocusTime time.Time lastFocusTime time.Time
@ -166,9 +163,9 @@ func (view *MainView) KeyEventHandler(roomView *RoomView, key *tcell.EventKey) *
if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt { if key.Modifiers() == tcell.ModCtrl || key.Modifiers() == tcell.ModAlt {
switch k { switch k {
case tcell.KeyDown: case tcell.KeyDown:
view.SwitchRoom(view.currentRoomIndex + 1) view.SwitchRoom(view.roomList.Next())
case tcell.KeyUp: case tcell.KeyUp:
view.SwitchRoom(view.currentRoomIndex - 1) view.SwitchRoom(view.roomList.Previous())
default: default:
return key return key
} }
@ -241,9 +238,7 @@ func (view *MainView) MouseEventHandler(roomView *RoomView, event *tcell.EventMo
} else if isInArea(x, y, view.roomList) && event.Buttons() == tcell.Button1 { } else if isInArea(x, y, view.roomList) && event.Buttons() == tcell.Button1 {
_, rly, _, _ := msgView.GetRect() _, rly, _, _ := msgView.GetRect()
n := y - rly + 1 n := y - rly + 1
if n >= 0 && n < len(view.roomIDs) { view.SwitchRoom(view.roomList.Get(n))
view.SwitchRoom(n)
}
} else { } else {
debug.Print("Unhandled mouse event:", event.Buttons(), event.Modifiers(), x, y) debug.Print("Unhandled mouse event:", event.Buttons(), event.Modifiers(), x, y)
} }
@ -253,35 +248,24 @@ func (view *MainView) MouseEventHandler(roomView *RoomView, event *tcell.EventMo
return event return event
} }
func (view *MainView) CurrentRoomID() string { func (view *MainView) SwitchRoom(room *rooms.Room) {
if len(view.roomIDs) == 0 { view.roomView.SwitchToPage(room.ID)
return "" roomView := view.rooms[room.ID]
}
return view.roomIDs[view.currentRoomIndex]
}
func (view *MainView) SwitchRoom(roomIndex int) {
if roomIndex < 0 {
roomIndex = len(view.roomIDs) - 1
}
if len(view.roomIDs) == 0 {
return
}
view.currentRoomIndex = roomIndex % len(view.roomIDs)
view.roomView.SwitchToPage(view.CurrentRoomID())
roomView := view.rooms[view.CurrentRoomID()]
if roomView.MessageView().ScrollOffset == 0 { if roomView.MessageView().ScrollOffset == 0 {
roomView.Room.MarkRead() roomView.Room.MarkRead()
} }
view.roomList.SetSelected(roomView.Room) view.roomList.SetSelected(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)) {
roomView, ok := view.rooms[view.CurrentRoomID()] room := view.roomList.Selected()
if ok { if room != nil {
delegate(roomView) roomView, ok := view.rooms[room.ID]
if ok {
delegate(roomView)
}
} }
} }
@ -294,78 +278,67 @@ func (view *MainView) SaveAllHistory() {
} }
} }
func (view *MainView) addRoom(index int, room string) { func (view *MainView) addRoomPage(room *rooms.Room) {
roomStore := view.matrix.GetRoom(room)
view.roomList.Add(roomStore) if !view.roomView.HasPage(room.ID) {
if !view.roomView.HasPage(room) { roomView := NewRoomView(view, room).
roomView := NewRoomView(view, roomStore).
SetInputSubmitFunc(view.InputSubmit). SetInputSubmitFunc(view.InputSubmit).
SetInputChangedFunc(view.InputChanged). SetInputChangedFunc(view.InputChanged).
SetInputCapture(view.KeyEventHandler). SetInputCapture(view.KeyEventHandler).
SetMouseCapture(view.MouseEventHandler) SetMouseCapture(view.MouseEventHandler)
view.rooms[room] = roomView view.rooms[room.ID] = roomView
view.roomView.AddPage(room, roomView, true, false) view.roomView.AddPage(room.ID, roomView, true, false)
roomView.UpdateUserList() roomView.UpdateUserList()
count, err := roomView.LoadHistory(view.matrix, view.config.HistoryDir) count, err := roomView.LoadHistory(view.matrix, view.config.HistoryDir)
if err != nil { if err != nil {
debug.Printf("Failed to load history of %s: %v", roomView.Room.GetTitle(), err) debug.Printf("Failed to load history of %s: %v", roomView.Room.GetTitle(), err)
} else if count <= 0 { } else if count <= 0 {
go view.LoadHistory(room, true) go view.LoadHistory(room.ID, true)
} }
} }
} }
func (view *MainView) GetRoom(id string) ifc.RoomView { func (view *MainView) GetRoom(roomID string) ifc.RoomView {
return view.rooms[id] return view.rooms[roomID]
} }
func (view *MainView) HasRoom(room string) bool { func (view *MainView) AddRoom(roomID string) {
for _, existingRoom := range view.roomIDs { if view.roomList.Contains(roomID) {
if existingRoom == room {
return true
}
}
return false
}
func (view *MainView) AddRoom(room string) {
if view.HasRoom(room) {
return return
} }
view.roomIDs = append(view.roomIDs, room) room := view.matrix.GetRoom(roomID)
view.addRoom(len(view.roomIDs)-1, room) view.roomList.Add(room)
view.addRoomPage(room)
} }
func (view *MainView) RemoveRoom(room string) { func (view *MainView) RemoveRoom(roomID string) {
roomView := view.GetRoom(room) roomView := view.GetRoom(roomID)
if roomView == nil { if roomView == nil {
return return
} }
removeIndex := 0
if view.CurrentRoomID() == room {
removeIndex = view.currentRoomIndex
view.SwitchRoom(view.currentRoomIndex - 1)
} else {
removeIndex = sort.StringSlice(view.roomIDs).Search(room)
}
view.roomList.Remove(roomView.MxRoom()) view.roomList.Remove(roomView.MxRoom())
view.roomIDs = append(view.roomIDs[:removeIndex], view.roomIDs[removeIndex+1:]...) view.SwitchRoom(view.roomList.Selected())
view.roomView.RemovePage(room)
delete(view.rooms, room) view.roomView.RemovePage(roomID)
delete(view.rooms, roomID)
view.parent.Render() view.parent.Render()
} }
func (view *MainView) SetRooms(rooms []string) { func (view *MainView) SetRooms(roomIDs []string) {
view.roomIDs = rooms
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, room := range rooms { for index, roomID := range roomIDs {
view.addRoom(index, room) room := view.matrix.GetRoom(roomID)
view.roomList.Add(room)
view.addRoomPage(room)
if index == len(roomIDs)-1 {
view.SwitchRoom(room)
}
} }
view.SwitchRoom(0)
} }
func (view *MainView) SetTyping(room string, users []string) { func (view *MainView) SetTyping(room string, users []string) {
@ -385,7 +358,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.ID == view.CurrentRoomID() isCurrent := room == view.roomList.Selected()
// 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())
@ -408,6 +381,7 @@ func (view *MainView) NotifyMessage(room *rooms.Room, message ifc.Message, shoul
} }
message.SetIsHighlight(should.Highlight) message.SetIsHighlight(should.Highlight)
view.roomList.Bump(room)
} }
func (view *MainView) LoadHistory(room string, initial bool) { func (view *MainView) LoadHistory(room string, initial bool) {