diff --git a/interface/ui.go b/interface/ui.go index 83fa7da..ec85b0f 100644 --- a/interface/ui.go +++ b/interface/ui.go @@ -49,7 +49,6 @@ type GomuksUI interface { type MainView interface { GetRoom(roomID string) RoomView - HasRoom(roomID string) bool AddRoom(roomID string) RemoveRoom(roomID string) SetRooms(roomIDs []string) diff --git a/lib/open/open_windows.go b/lib/open/open_windows.go index aced662..374ad21 100644 --- a/lib/open/open_windows.go +++ b/lib/open/open_windows.go @@ -17,7 +17,9 @@ package open import ( + "os" "os/exec" + "path/filepath" ) const FileProtocolHandler = "url.dll,FileProtocolHandler" diff --git a/ui/room-list.go b/ui/room-list.go index 1162ad5..7637d4f 100644 --- a/ui/room-list.go +++ b/ui/room-list.go @@ -29,7 +29,6 @@ import ( type RoomList struct { *tview.Box - indices map[*rooms.Room]int items []*rooms.Room selected *rooms.Room @@ -43,9 +42,8 @@ type RoomList struct { func NewRoomList() *RoomList { return &RoomList{ - Box: tview.NewBox(), - indices: make(map[*rooms.Room]int), - items: []*rooms.Room{}, + Box: tview.NewBox(), + items: []*rooms.Room{}, mainTextColor: tcell.ColorWhite, selectedTextColor: tcell.ColorWhite, @@ -53,28 +51,49 @@ func NewRoomList() *RoomList { } } -func (list *RoomList) Add(room *rooms.Room) { - list.indices[room] = len(list.items) - list.items = append(list.items, room) - if list.selected == nil { - list.selected = room +func (list *RoomList) Contains(roomID string) bool { + for _, room := range list.items { + if room.ID == roomID { + return true + } } + return false +} + +func (list *RoomList) Add(room *rooms.Room) { + list.items = append(list.items, room) } func (list *RoomList) Remove(room *rooms.Room) { - index, ok := list.indices[room] - if !ok { - return - } - delete(list.indices, room) - list.items = append(list.items[0:index], list.items[index+1:]...) - if len(list.items) == 0 { - list.selected = nil + index := list.Index(room) + if index != -1 { + list.items = append(list.items[0:index], list.items[index+1:]...) + if room == list.selected { + if index > 0 { + list.selected = list.items[index-1] + } else if len(list.items) > 0 { + 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() { - list.indices = make(map[*rooms.Room]int) list.items = []*rooms.Room{} list.selected = nil } @@ -83,11 +102,55 @@ func (list *RoomList) SetSelected(room *rooms.Room) { list.selected = room } -func (list *RoomList) Get(n int) *rooms.Room { - if n < 0 || n >= len(list.items) { +func (list *RoomList) HasSelected() bool { + 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 + } 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. @@ -98,13 +161,16 @@ func (list *RoomList) Draw(screen tcell.Screen) { bottomLimit := y + height var offset int - currentItemIndex, hasSelected := list.indices[list.selected] - if hasSelected && currentItemIndex >= height { + currentItemIndex := list.Index(list.selected) + if currentItemIndex >= height { offset = currentItemIndex + 1 - height } // 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 { continue } diff --git a/ui/view-main.go b/ui/view-main.go index c693fcd..e9350e7 100644 --- a/ui/view-main.go +++ b/ui/view-main.go @@ -18,7 +18,6 @@ package ui import ( "fmt" - "sort" "strings" "time" "unicode" @@ -39,11 +38,9 @@ import ( type MainView struct { *tview.Flex - roomList *RoomList - roomView *tview.Pages - rooms map[string]*RoomView - currentRoomIndex int - roomIDs []string + roomList *RoomList + roomView *tview.Pages + rooms map[string]*RoomView 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 { switch k { case tcell.KeyDown: - view.SwitchRoom(view.currentRoomIndex + 1) + view.SwitchRoom(view.roomList.Next()) case tcell.KeyUp: - view.SwitchRoom(view.currentRoomIndex - 1) + view.SwitchRoom(view.roomList.Previous()) default: 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 { _, rly, _, _ := msgView.GetRect() n := y - rly + 1 - if n >= 0 && n < len(view.roomIDs) { - view.SwitchRoom(n) - } + view.SwitchRoom(view.roomList.Get(n)) } else { 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 } -func (view *MainView) CurrentRoomID() string { - if len(view.roomIDs) == 0 { - return "" - } - 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()] +func (view *MainView) SwitchRoom(room *rooms.Room) { + view.roomView.SwitchToPage(room.ID) + roomView := view.rooms[room.ID] if roomView.MessageView().ScrollOffset == 0 { roomView.Room.MarkRead() } - view.roomList.SetSelected(roomView.Room) + view.roomList.SetSelected(room) view.parent.app.SetFocus(view) view.parent.Render() } func (view *MainView) Focus(delegate func(p tview.Primitive)) { - roomView, ok := view.rooms[view.CurrentRoomID()] - if ok { - delegate(roomView) + room := view.roomList.Selected() + if room != nil { + 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) { - roomStore := view.matrix.GetRoom(room) +func (view *MainView) addRoomPage(room *rooms.Room) { - view.roomList.Add(roomStore) - if !view.roomView.HasPage(room) { - roomView := NewRoomView(view, roomStore). + if !view.roomView.HasPage(room.ID) { + roomView := NewRoomView(view, room). SetInputSubmitFunc(view.InputSubmit). SetInputChangedFunc(view.InputChanged). SetInputCapture(view.KeyEventHandler). SetMouseCapture(view.MouseEventHandler) - view.rooms[room] = roomView - view.roomView.AddPage(room, roomView, true, false) + view.rooms[room.ID] = roomView + view.roomView.AddPage(room.ID, roomView, true, false) roomView.UpdateUserList() count, err := roomView.LoadHistory(view.matrix, view.config.HistoryDir) if err != nil { debug.Printf("Failed to load history of %s: %v", roomView.Room.GetTitle(), err) } else if count <= 0 { - go view.LoadHistory(room, true) + go view.LoadHistory(room.ID, true) } } } -func (view *MainView) GetRoom(id string) ifc.RoomView { - return view.rooms[id] +func (view *MainView) GetRoom(roomID string) ifc.RoomView { + return view.rooms[roomID] } -func (view *MainView) HasRoom(room string) bool { - for _, existingRoom := range view.roomIDs { - if existingRoom == room { - return true - } - } - return false -} - -func (view *MainView) AddRoom(room string) { - if view.HasRoom(room) { +func (view *MainView) AddRoom(roomID string) { + if view.roomList.Contains(roomID) { return } - view.roomIDs = append(view.roomIDs, room) - view.addRoom(len(view.roomIDs)-1, room) + room := view.matrix.GetRoom(roomID) + view.roomList.Add(room) + view.addRoomPage(room) } -func (view *MainView) RemoveRoom(room string) { - roomView := view.GetRoom(room) +func (view *MainView) RemoveRoom(roomID string) { + roomView := view.GetRoom(roomID) if roomView == nil { 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.roomIDs = append(view.roomIDs[:removeIndex], view.roomIDs[removeIndex+1:]...) - view.roomView.RemovePage(room) - delete(view.rooms, room) + view.SwitchRoom(view.roomList.Selected()) + + view.roomView.RemovePage(roomID) + delete(view.rooms, roomID) + view.parent.Render() } -func (view *MainView) SetRooms(rooms []string) { - view.roomIDs = rooms +func (view *MainView) SetRooms(roomIDs []string) { view.roomList.Clear() view.roomView.Clear() view.rooms = make(map[string]*RoomView) - for index, room := range rooms { - view.addRoom(index, room) + for index, roomID := range roomIDs { + 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) { @@ -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) { // 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. 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) + view.roomList.Bump(room) } func (view *MainView) LoadHistory(room string, initial bool) {