Make scrollable channel pane

This commit is contained in:
erroneousboat 2016-10-01 12:48:15 +02:00
parent e71602c214
commit aa7830ce35
4 changed files with 79 additions and 31 deletions

View File

@ -19,12 +19,14 @@ Bugs:
- [ ] GetMessages for a channel can result in `json: cannot unmarshal number
into Go value of type string` https://github.com/nlopes/slack/issues/92
- [ ] docs at exported functions
- [ ] incoming message event.go probably need a type switch
- [ ] set channel on start
Features:
- [x] channel name in chat pane
- [x] new message indicator
- [x] scrolling in chat pane
- [ ] group channels, im channels
- [ ] incomming message event.go probably need a type switch
- [ ] scrolling in channel pane
- [x] group channels, im channels
- [x] scrolling in channel pane
- [ ] remove unsubscribed or closed channels/groups/im

View File

@ -11,13 +11,11 @@ import (
type Channels struct {
List *termui.List
SelectedChannel int
Offset int
CursorPosition int
}
type SlackChannel struct {
Name string
ID string
}
// CreateChannels is the constructor for the Channels component
func CreateChannels(svc *service.SlackService, inputHeight int) *Channels {
channels := &Channels{
List: termui.NewList(),
@ -27,6 +25,8 @@ func CreateChannels(svc *service.SlackService, inputHeight int) *Channels {
channels.List.Height = termui.TermHeight() - inputHeight
channels.SelectedChannel = 0
channels.Offset = 0
channels.CursorPosition = channels.List.InnerBounds().Min.Y
channels.GetChannels(svc)
@ -37,9 +37,16 @@ func CreateChannels(svc *service.SlackService, inputHeight int) *Channels {
func (c *Channels) Buffer() termui.Buffer {
buf := c.List.Buffer()
for y, item := range c.List.Items {
for i, item := range c.List.Items[c.Offset:] {
y := c.List.InnerBounds().Min.Y + i
if y > c.List.InnerBounds().Max.Y-1 {
break
}
var cells []termui.Cell
if y == c.SelectedChannel {
if y == c.CursorPosition {
cells = termui.DefaultTxBuilder.Build(
item, termui.ColorBlack, termui.ColorWhite)
} else {
@ -52,13 +59,23 @@ func (c *Channels) Buffer() termui.Buffer {
x := 0
for _, cell := range cells {
width := cell.Width()
buf.Set(
c.List.InnerBounds().Min.X+x,
c.List.InnerBounds().Min.Y+y,
cell,
)
buf.Set(c.List.InnerBounds().Min.X+x, y, cell)
x += width
}
// When not at the end of the pane fill it up empty characters
for x < c.List.InnerBounds().Max.X-1 {
if y == c.CursorPosition {
buf.Set(x+1, y,
termui.Cell{
Ch: ' ', Fg: termui.ColorBlack, Bg: termui.ColorWhite,
},
)
} else {
buf.Set(x+1, y, termui.Cell{Ch: ' '})
}
x++
}
}
return buf
@ -85,9 +102,6 @@ func (c *Channels) SetY(y int) {
}
// GetChannels will get all available channels from the SlackService
// and add them to the List as well as to the SlackChannels, this is done
// to better relate the ID and name given to Channels, for Chat.GetMessages.
// See event.go actionChangeChannel for more explanation
func (c *Channels) GetChannels(svc *service.SlackService) {
for _, slackChan := range svc.GetChannels() {
c.List.Items = append(c.List.Items, fmt.Sprintf(" %s", slackChan.Name))
@ -103,6 +117,7 @@ func (c *Channels) SetSelectedChannel(index int) {
func (c *Channels) MoveCursorUp() {
if c.SelectedChannel > 0 {
c.SetSelectedChannel(c.SelectedChannel - 1)
c.ScrollUp()
c.ClearNewMessageIndicator()
}
}
@ -111,16 +126,37 @@ func (c *Channels) MoveCursorUp() {
func (c *Channels) MoveCursorDown() {
if c.SelectedChannel < len(c.List.Items)-1 {
c.SetSelectedChannel(c.SelectedChannel + 1)
c.ScrollDown()
c.ClearNewMessageIndicator()
}
}
func (c *Channels) ScrollUp() {
if c.CursorPosition == c.List.InnerBounds().Min.Y {
if c.Offset > 0 {
c.Offset--
}
} else {
c.CursorPosition--
}
}
func (c *Channels) ScrollDown() {
if c.CursorPosition == c.List.InnerBounds().Max.Y-1 {
if c.Offset < len(c.List.Items)-1 {
c.Offset++
}
} else {
c.CursorPosition++
}
}
// NewMessage will be called when a new message arrives and will
// render an asterisk in front of the channel name
func (c *Channels) NewMessage(svc *service.SlackService, channelID string) {
var index int
// Get the correct Channel from SlackChannels
// Get the correct Channel from svc.Channels
for i, channel := range svc.Channels {
if channelID == channel.ID {
index = i
@ -129,7 +165,7 @@ func (c *Channels) NewMessage(svc *service.SlackService, channelID string) {
}
if !strings.Contains(c.List.Items[index], "*") {
// The order of SlackChannels relates to the order of
// The order of svc.Channels relates to the order of
// List.Items, index will be the index of the channel
c.List.Items[index] = fmt.Sprintf("* %s", strings.TrimSpace(c.List.Items[index]))
}

View File

@ -94,10 +94,14 @@ func incomingMessageHandler(ctx *context.AppContext) {
ctx.View.Chat.AddMessage(m)
termui.Render(ctx.View.Chat)
// TODO: set Chat.Offset to 0?
// TODO: set Chat.Offset to 0, to automatically scroll
// down?
}
// Set new message indicator for channel
// Set new message indicator for channel, I'm leaving
// this here because I also want to be notified when
// I'm currently in a channel but not in the terminal
// window (tmux)
actionNewMessage(ctx, ev.Channel)
}
}

View File

@ -55,14 +55,14 @@ func (s *SlackService) GetChannels() []Channel {
// TODO: json: cannot unmarshal number into Go value of type string, GetMessages
// Groups
// slackGroups, err := s.Client.GetGroups(true)
// if err != nil {
// chans = append(chans, Channel{})
// }
// for _, grp := range slackGroups {
// s.SlackChannels = append(s.SlackChannels, grp)
// chans = append(chans, Channel{grp.ID, grp.Name})
// }
slackGroups, err := s.Client.GetGroups(true)
if err != nil {
chans = append(chans, Channel{})
}
for _, grp := range slackGroups {
s.SlackChannels = append(s.SlackChannels, grp)
chans = append(chans, Channel{grp.ID, grp.Name})
}
// IM
slackIM, err := s.Client.GetIMChannels()
@ -71,7 +71,13 @@ func (s *SlackService) GetChannels() []Channel {
}
for _, im := range slackIM {
s.SlackChannels = append(s.SlackChannels, im)
chans = append(chans, Channel{im.ID, im.User})
// Uncover name
name, ok := s.UserCache[im.User]
if !ok {
name = im.User
}
chans = append(chans, Channel{im.ID, name})
}
s.Channels = chans