gomu/start.go

285 lines
5.9 KiB
Go
Raw Normal View History

2020-06-22 00:05:56 +08:00
// Copyright (C) 2020 Raziman
2020-06-19 16:29:51 +08:00
package main
import (
2020-06-25 10:46:45 +08:00
"os"
"strings"
2020-06-25 10:46:45 +08:00
2020-06-19 16:29:51 +08:00
"github.com/gdamore/tcell"
"github.com/rivo/tview"
2020-06-24 20:09:47 +08:00
"github.com/spf13/viper"
2020-06-19 16:29:51 +08:00
)
2020-07-06 17:02:59 +08:00
// created so we can keep track of childrens in slices
type Panel interface {
HasFocus() bool
SetBorderColor(color tcell.Color) *tview.Box
SetTitleColor(color tcell.Color) *tview.Box
SetTitle(s string) *tview.Box
GetTitle() string
}
type Gomu struct {
App *tview.Application
PlayingBar *PlayingBar
Queue *Queue
Playlist *Playlist
Player *Player
Pages *tview.Pages
2020-07-06 17:02:59 +08:00
PrevPanel Panel
PopupBg tcell.Color
TextColor tcell.Color
AccentColor tcell.Color
2020-07-06 17:02:59 +08:00
Panels []Panel
}
// Creates new instance of gomu with default values
func NewGomu() *Gomu {
gomu := &Gomu{
PopupBg: tcell.GetColor("#0A0F14"),
TextColor: tcell.ColorWhite,
AccentColor: tcell.ColorDarkCyan,
}
return gomu
}
2020-07-06 17:02:59 +08:00
// Initialize childrens/panels this is seperated from
// constructor function `NewGomu` so that we can
// test independently
2020-07-06 17:02:59 +08:00
func (g *Gomu) InitPanels(app *tview.Application) {
g.App = app
g.PlayingBar = NewPlayingBar()
g.Queue = NewQueue()
g.Playlist = NewPlaylist()
g.Player = &Player{}
g.Pages = tview.NewPages()
2020-07-06 17:02:59 +08:00
g.Panels = []Panel{g.Playlist, g.Queue, g.PlayingBar}
}
// cycle between panels
func (g *Gomu) CyclePanels() Panel {
var anyChildHasFocus bool
for i, child := range g.Panels {
if child.HasFocus() {
anyChildHasFocus = true
var nextChild Panel
// if its the last element set the child back to one
if i == len(g.Panels)-1 {
nextChild = g.Panels[0]
} else {
nextChild = g.Panels[i+1]
}
g.SetFocusPanel(nextChild)
g.PrevPanel = nextChild
return nextChild
}
}
first := g.Panels[0]
if !anyChildHasFocus {
g.SetFocusPanel(first)
}
g.PrevPanel = first
return first
}
// changes title and border color when focusing panel
// and changes color of the previous panel as well
func (g *Gomu) SetFocusPanel(panel Panel) {
g.App.SetFocus(panel.(tview.Primitive))
panel.SetBorderColor(g.AccentColor)
panel.SetTitleColor(g.AccentColor)
if g.PrevPanel == nil {
return
}
g.SetUnfocusPanel(g.PrevPanel)
}
// removes the color of the given panel
func (g *Gomu) SetUnfocusPanel(panel Panel) {
g.PrevPanel.SetBorderColor(g.TextColor)
g.PrevPanel.SetTitleColor((g.TextColor))
}
2020-07-06 17:02:59 +08:00
// one single instance of global variable
var gomu *Gomu
2020-06-26 12:54:48 +08:00
func start(application *tview.Application) {
2020-06-19 16:29:51 +08:00
// override default border
// change double line border to one line border when focused
tview.Borders.HorizontalFocus = tview.Borders.Horizontal
tview.Borders.VerticalFocus = tview.Borders.Vertical
tview.Borders.TopLeftFocus = tview.Borders.TopLeft
tview.Borders.TopRightFocus = tview.Borders.TopRight
tview.Borders.BottomLeftFocus = tview.Borders.BottomLeft
tview.Borders.BottomRightFocus = tview.Borders.BottomRight
2020-06-19 16:29:51 +08:00
tview.Styles.PrimitiveBackgroundColor = tcell.ColorDefault
tview.Styles.BorderColor = tcell.ColorWhite
gomu = NewGomu()
2020-07-06 17:02:59 +08:00
gomu.InitPanels(application)
2020-06-19 16:29:51 +08:00
2020-06-25 14:12:19 +08:00
2020-07-02 16:11:10 +08:00
appLog("start app")
flex := Layout(gomu)
gomu.Pages.AddPage("main", flex, true, true)
2020-06-25 14:12:19 +08:00
gomu.Playlist.SetBorderColor(gomu.AccentColor)
gomu.Playlist.SetTitleColor(gomu.AccentColor)
gomu.PrevPanel = gomu.Playlist
2020-06-25 14:12:19 +08:00
2020-06-19 16:29:51 +08:00
2020-06-26 12:54:48 +08:00
application.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
2020-06-19 16:29:51 +08:00
switch event.Key() {
// cycle through each section
case tcell.KeyTAB:
2020-07-06 17:02:59 +08:00
gomu.CyclePanels()
2020-06-19 16:29:51 +08:00
}
name, _ := gomu.Pages.GetFrontPage()
// disables keybindings when writing in input fields
if strings.Contains(name, "-input-") {
return event
}
2020-06-19 16:29:51 +08:00
switch event.Rune() {
case 'q':
2020-06-19 16:42:30 +08:00
2020-06-25 10:46:45 +08:00
if !viper.GetBool("confirm_on_exit") {
2020-06-26 12:54:48 +08:00
application.Stop()
2020-06-24 20:09:47 +08:00
}
2020-06-26 12:54:48 +08:00
confirmationPopup("Are you sure to exit?", func(_ int, label string) {
2020-06-19 16:42:30 +08:00
2020-06-19 16:29:51 +08:00
if label == "yes" {
2020-06-26 12:54:48 +08:00
application.Stop()
2020-06-19 16:29:51 +08:00
} else {
gomu.Pages.RemovePage("confirmation-popup")
2020-06-19 16:29:51 +08:00
}
})
2020-06-21 00:00:17 +08:00
case ' ':
gomu.Player.TogglePause()
2020-06-21 23:47:12 +08:00
case '+':
v := int(gomu.Player.volume*10) + 50
2020-06-26 17:09:15 +08:00
if v < 50 {
vol := gomu.Player.Volume(0.5)
2020-06-26 17:09:15 +08:00
volumePopup(vol)
}
2020-06-21 23:47:12 +08:00
case '-':
v := int(gomu.Player.volume*10) + 50
2020-06-26 17:09:15 +08:00
if v > 0 {
vol := gomu.Player.Volume(-0.5)
2020-06-26 17:09:15 +08:00
volumePopup(vol)
}
2020-06-21 00:00:17 +08:00
2020-06-23 18:42:18 +08:00
case 'n':
gomu.Player.Skip()
2020-06-23 18:42:18 +08:00
2020-06-27 00:09:59 +08:00
case '?':
name, _ := gomu.Pages.GetFrontPage()
2020-06-27 00:09:59 +08:00
if name == "help-page" {
gomu.Pages.RemovePage(name)
gomu.App.SetFocus(gomu.PrevPanel.(tview.Primitive))
2020-06-27 00:09:59 +08:00
} else {
helpPopup()
}
2020-06-19 16:29:51 +08:00
}
return event
})
// fix transparent background issue
2020-06-26 12:54:48 +08:00
application.SetBeforeDrawFunc(func(screen tcell.Screen) bool {
2020-06-19 16:29:51 +08:00
screen.Clear()
return false
})
// main loop
if err := application.SetRoot(gomu.Pages, true).SetFocus(gomu.Playlist).Run(); err != nil {
2020-07-02 16:11:10 +08:00
appLog(err)
2020-06-19 16:29:51 +08:00
}
}
2020-06-24 20:09:47 +08:00
func readConfig() {
2020-06-26 12:54:48 +08:00
home, err := os.UserHomeDir()
2020-06-25 10:46:45 +08:00
configPath := home + "/.config/gomu/config"
if err != nil {
2020-07-02 16:11:10 +08:00
appLog(err)
2020-06-25 10:46:45 +08:00
}
viper.SetConfigName("config")
viper.SetConfigType("yaml")
2020-06-24 20:09:47 +08:00
viper.AddConfigPath("/etc/gomu")
2020-06-25 10:46:45 +08:00
viper.AddConfigPath(home + "/.gomu")
2020-06-24 20:09:47 +08:00
viper.AddConfigPath("$HOME/.config/gomu")
if err := viper.ReadInConfig(); err != nil {
2020-06-25 10:46:45 +08:00
viper.SetDefault("music_dir", "~/music")
viper.SetDefault("confirm_on_exit", true)
2020-06-26 17:09:15 +08:00
viper.SetDefault("confirm_bulk_add", true)
2020-07-04 09:47:41 +08:00
viper.SetDefault("popup_timeout", "5s")
2020-06-25 10:46:45 +08:00
// creates gomu config dir if does not exist
if _, err := os.Stat(configPath); err != nil {
2020-06-26 12:54:48 +08:00
if err := os.MkdirAll(home+"/.config/gomu", 0755); err != nil {
2020-07-02 16:11:10 +08:00
appLog(err)
2020-06-25 10:46:45 +08:00
}
}
// if config file was not found
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
if err := viper.SafeWriteConfigAs(configPath); err != nil {
2020-07-02 16:11:10 +08:00
appLog(err)
2020-06-25 10:46:45 +08:00
}
}
2020-06-24 20:09:47 +08:00
}
}
2020-07-03 00:50:18 +08:00
// layout is used to organize the panels
func Layout(gomu *Gomu) *tview.Flex {
2020-07-03 00:50:18 +08:00
flex := tview.NewFlex().
AddItem(gomu.Playlist, 0, 1, false).
2020-07-03 00:50:18 +08:00
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(gomu.Queue, 0, 7, false).
AddItem(gomu.PlayingBar, 0, 1, false), 0, 3, false)
2020-07-03 00:50:18 +08:00
return flex
}