Add keybinding controls view

This commit is contained in:
Adriano Caloiaro 2020-03-01 12:40:54 -05:00
parent 3537881a9b
commit 1c48832ee6
No known key found for this signature in database
GPG key ID: 9FFD0E7601F166AB
3 changed files with 109 additions and 40 deletions

View file

@ -12,25 +12,9 @@ import (
"github.com/faiface/beep/speaker"
)
// TogglePause pauses/unpauses audio when a channel is playing
func TogglePause(ctx *context.AppContext) {
// nothing to do if nothing has been streamed
if ctx.AudioStream == nil {
return
}
ctx.AudioStream.Close()
if !ctx.IsPlaying {
PlayChannel(ctx.CurrentChannel, ctx)
}
ctx.IsPlaying = !ctx.IsPlaying
}
// PlayChannel begins streaming the provided channel after fetching its playlist
// If a channel is already playing, the old stream is stopped first, clearing up resources.
// This function is asynchronous and creates a single streaming resource: he audio stream held by the application
// This function is *asynchronous* and creates a single streaming resource: the audio stream held by the application
// context. To clean up resources created by this function, Close() the application's audio stream.
func PlayChannel(chn *components.ChannelItem, ctx *context.AppContext) {
@ -59,14 +43,31 @@ func PlayChannel(chn *components.ChannelItem, ctx *context.AppContext) {
speaker.Play(ctx.AudioStream)
ctx.IsPlaying = true
setNowPlaying(chn, ctx)
updateNowPlaying(chn, ctx)
}
}()
}
func setNowPlaying(chn *components.ChannelItem, ctx *context.AppContext) {
// TogglePause pauses/unpauses audio when a channel is playing
func TogglePause(ctx *context.AppContext) {
// nothing to do if nothing has been streamed
if ctx.AudioStream == nil {
return
}
ctx.AudioStream.Close()
if !ctx.IsPlaying {
PlayChannel(ctx.CurrentChannel, ctx)
}
ctx.IsPlaying = !ctx.IsPlaying
}
func updateNowPlaying(chn *components.ChannelItem, ctx *context.AppContext) {
ctx.CurrentChannel = chn
cp := difm.GetCurrentlyPlaying(ctx)
ctx.View.App.QueueUpdateDraw(func() {
ctx.View.NowPlaying.Channel = chn
track := cp.Track

View file

@ -9,9 +9,9 @@ import (
"github.com/acaloiaro/dicli/context"
"github.com/acaloiaro/dicli/difm"
"github.com/acaloiaro/dicli/views"
"github.com/rivo/tview"
"github.com/gdamore/tcell"
"github.com/rivo/tview"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
@ -45,6 +45,37 @@ func main() {
}
func run() {
configureEventHandling()
configureUIComponents()
layout := buildUILayout()
err := ctx.View.App.
SetRoot(layout, true).
SetFocus(ctx.View.ChannelList).
Run()
if err != nil {
panic(err)
}
}
func buildUILayout() *tview.Flex {
main := tview.NewFlex()
main.SetDirection(tview.FlexRow)
flex := tview.NewFlex()
flex.
AddItem(ctx.View.ChannelList, 0, 1, false).
AddItem(ctx.View.NowPlaying, 0, 2, false)
main.
AddItem(flex, 0, 15, false).
AddItem(ctx.View.Keybindings, 0, 1, false)
return main
}
func configureEventHandling() {
ctx.View.App.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Rune() {
case 'q':
@ -62,28 +93,27 @@ func run() {
return event
})
}
func configureUIComponents() {
// configure the channel list
channels := difm.ListChannels()
for _, chn := range channels {
ctx.View.ChannelList.AddItem(chn.Name, "", 0, func() {
go func() {
chn := channels[ctx.View.ChannelList.GetCurrentItem()]
app.PlayChannel(&chn, ctx)
}()
chn := channels[ctx.View.ChannelList.GetCurrentItem()]
app.PlayChannel(&chn, ctx)
})
}
flex := tview.NewFlex()
flex.
AddItem(ctx.View.ChannelList, 0, 1, false).
AddItem(ctx.View.NowPlaying, 0, 2, false)
err := ctx.View.App.
SetRoot(flex, true).
SetFocus(ctx.View.ChannelList).
Run()
if err != nil {
panic(err)
// configure the keybinding view
bindings := []views.UIKeybinding{
views.UIKeybinding{Shortcut: "q", Description: "Quit", Func: func() {}},
views.UIKeybinding{Shortcut: "p", Description: "Pause", Func: func() {}},
views.UIKeybinding{Shortcut: "j", Description: "Scroll Up", Func: func() {}},
views.UIKeybinding{Shortcut: "k", Description: "Scroll Down", Func: func() {}},
views.UIKeybinding{Shortcut: "Enter", Description: "Play Selected", Func: func() {}},
}
ctx.View.Keybindings.Bindings = bindings
}

View file

@ -12,13 +12,29 @@ type AppView struct {
App *tview.Application
ChannelList *tview.List
NowPlaying *NowPlayingView
Keybindings *KeybindingView
}
// KeybindingView is a custom view for dispalying the keyboard bindings available to users
type KeybindingView struct {
*tview.Box
Bindings []UIKeybinding
}
// UIKeybinding is a helper struct for building a ControlsView
type UIKeybinding struct {
Shortcut string // a keybinding to bind to this control
Description string // a description of what the keybinding does
Func func() // the funcion to execute when the binding is pressed
}
// CreateAppView creates the primary application view of di-tui
func CreateAppView() *AppView {
return &AppView{
App: tview.NewApplication(),
ChannelList: createChannelList(),
NowPlaying: newNowPlaying(&components.ChannelItem{Name: "N/A"}),
NowPlaying: newNowPlaying(&components.ChannelItem{}),
Keybindings: createKeybindings(),
}
}
@ -48,16 +64,29 @@ func (n *NowPlayingView) Draw(screen tcell.Screen) {
x, y, width, _ := n.GetInnerRect()
line := fmt.Sprintf("%s[white] %s", "Channel:", n.Channel.Name)
tview.Print(screen, line, x, y, width, tview.AlignLeft, tcell.ColorYellow)
tview.Print(screen, line, x, y, width, tview.AlignLeft, tcell.ColorBlue)
line = fmt.Sprintf("%s[white] %s", "Artist:", n.Artist)
tview.Print(screen, line, x, y+1, width, tview.AlignLeft, tcell.ColorYellow)
tview.Print(screen, line, x, y+1, width, tview.AlignLeft, tcell.ColorBlue)
line = fmt.Sprintf("%s[white] %s", "Track:", n.Track)
tview.Print(screen, line, x, y+2, width, tview.AlignLeft, tcell.ColorYellow)
tview.Print(screen, line, x, y+2, width, tview.AlignLeft, tcell.ColorBlue)
}
// Draw draws this primitive onto the screen.
func (n *KeybindingView) Draw(screen tcell.Screen) {
n.Box.Draw(screen)
x, y, width, _ := n.GetInnerRect()
previousWidth := 0
for _, bnd := range n.Bindings {
line := fmt.Sprintf("(%s)[white] %s", bnd.Shortcut, bnd.Description)
tview.Print(screen, line, x+previousWidth, y, width, tview.AlignLeft, tcell.ColorBlue)
previousWidth += len(bnd.Shortcut) + len(bnd.Description) + 5
}
}
func createChannelList() *tview.List {
list := tview.NewList()
list.
@ -67,3 +96,12 @@ func createChannelList() *tview.List {
return list
}
func createKeybindings() *KeybindingView {
kbv := &KeybindingView{Box: tview.NewBox()}
kbv.
SetBorder(true).
SetTitle(" Key Bindings ")
return kbv
}