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"
|
2020-07-01 21:21:46 +08:00
|
|
|
"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-04 16:16:57 +08:00
|
|
|
// var (
|
|
|
|
// app *tview.Application
|
|
|
|
// playingBar *PlayingBar
|
|
|
|
// queue *Queue
|
|
|
|
// playlist *Playlist
|
|
|
|
// player *Player
|
|
|
|
// pages *tview.Pages
|
|
|
|
// prevPanel Children
|
|
|
|
// popupBg = tcell.GetColor("#0A0F14")
|
|
|
|
// textColor = tcell.ColorWhite
|
|
|
|
// accentColor = tcell.ColorDarkCyan
|
|
|
|
// )
|
|
|
|
|
|
|
|
type Gomu struct {
|
|
|
|
App *tview.Application
|
|
|
|
PlayingBar *PlayingBar
|
|
|
|
Queue *Queue
|
|
|
|
Playlist *Playlist
|
|
|
|
Player *Player
|
|
|
|
Pages *tview.Pages
|
|
|
|
PrevPanel Children
|
|
|
|
PopupBg tcell.Color
|
|
|
|
TextColor tcell.Color
|
|
|
|
AccentColor tcell.Color
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize childrens/panels this is seperated from
|
|
|
|
// constructor function `NewGomu` so that we can
|
|
|
|
// test independently
|
|
|
|
func (g *Gomu) InitChildrens(app *tview.Application) {
|
|
|
|
g.App = app
|
|
|
|
g.PlayingBar = NewPlayingBar()
|
|
|
|
g.Queue = NewQueue()
|
|
|
|
g.Playlist = NewPlaylist()
|
|
|
|
g.Player = &Player{}
|
|
|
|
g.Pages = tview.NewPages()
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2020-07-04 16:16:57 +08:00
|
|
|
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
|
2020-07-04 16:16:57 +08:00
|
|
|
tview.Styles.BorderColor = tcell.ColorWhite
|
|
|
|
|
|
|
|
gomu = NewGomu()
|
|
|
|
gomu.InitChildrens(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")
|
|
|
|
|
2020-07-04 16:16:57 +08:00
|
|
|
flex := Layout(gomu)
|
|
|
|
gomu.Pages.AddPage("main", flex, true, true)
|
2020-06-25 14:12:19 +08:00
|
|
|
|
2020-07-04 16:16:57 +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-07-04 16:16:57 +08:00
|
|
|
childrens := []Children{gomu.Playlist, gomu.Queue, gomu.PlayingBar}
|
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-04 16:16:57 +08:00
|
|
|
gomu.PrevPanel = cycleChildren(gomu, childrens)
|
2020-06-19 16:29:51 +08:00
|
|
|
}
|
|
|
|
|
2020-07-04 16:16:57 +08:00
|
|
|
name, _ := gomu.Pages.GetFrontPage()
|
2020-07-01 21:21:46 +08:00
|
|
|
|
|
|
|
// 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 {
|
2020-07-04 16:16:57 +08:00
|
|
|
gomu.Pages.RemovePage("confirmation-popup")
|
2020-06-19 16:29:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
2020-06-21 00:00:17 +08:00
|
|
|
case ' ':
|
2020-07-04 16:16:57 +08:00
|
|
|
gomu.Player.TogglePause()
|
2020-06-21 23:47:12 +08:00
|
|
|
|
|
|
|
case '+':
|
2020-07-04 16:16:57 +08:00
|
|
|
v := int(gomu.Player.volume*10) + 50
|
2020-06-26 17:09:15 +08:00
|
|
|
if v < 50 {
|
2020-07-04 16:16:57 +08:00
|
|
|
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 '-':
|
2020-07-04 16:16:57 +08:00
|
|
|
v := int(gomu.Player.volume*10) + 50
|
2020-06-26 17:09:15 +08:00
|
|
|
if v > 0 {
|
2020-07-04 16:16:57 +08:00
|
|
|
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':
|
2020-07-04 16:16:57 +08:00
|
|
|
gomu.Player.Skip()
|
2020-06-23 18:42:18 +08:00
|
|
|
|
2020-06-27 00:09:59 +08:00
|
|
|
case '?':
|
|
|
|
|
2020-07-04 16:16:57 +08:00
|
|
|
name, _ := gomu.Pages.GetFrontPage()
|
2020-06-27 00:09:59 +08:00
|
|
|
|
|
|
|
if name == "help-page" {
|
2020-07-04 16:16:57 +08:00
|
|
|
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
|
2020-07-04 16:16:57 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// created so we can keep track of childrens in slices
|
|
|
|
type Children interface {
|
|
|
|
HasFocus() bool
|
|
|
|
SetBorderColor(color tcell.Color) *tview.Box
|
|
|
|
SetTitleColor(color tcell.Color) *tview.Box
|
|
|
|
SetTitle(s string) *tview.Box
|
|
|
|
GetTitle() string
|
|
|
|
}
|
|
|
|
|
2020-07-04 16:16:57 +08:00
|
|
|
func cycleChildren(gomu *Gomu, childrens []Children) Children {
|
2020-06-19 16:29:51 +08:00
|
|
|
|
2020-07-04 16:16:57 +08:00
|
|
|
focusedColor := gomu.AccentColor
|
|
|
|
unfocusedColor := gomu.TextColor
|
2020-06-19 16:29:51 +08:00
|
|
|
anyChildHasFocus := false
|
|
|
|
|
|
|
|
for i, child := range childrens {
|
|
|
|
|
|
|
|
if child.HasFocus() {
|
|
|
|
|
|
|
|
anyChildHasFocus = true
|
|
|
|
|
|
|
|
var nextChild Children
|
|
|
|
|
|
|
|
// if its the last element set the child back to one
|
2020-06-19 16:42:30 +08:00
|
|
|
if i == len(childrens)-1 {
|
2020-06-19 16:29:51 +08:00
|
|
|
nextChild = childrens[0]
|
|
|
|
} else {
|
2020-06-19 16:42:30 +08:00
|
|
|
nextChild = childrens[i+1]
|
2020-06-19 16:29:51 +08:00
|
|
|
}
|
|
|
|
|
2020-06-19 16:42:30 +08:00
|
|
|
child.SetBorderColor(unfocusedColor)
|
2020-06-19 16:29:51 +08:00
|
|
|
child.SetTitleColor(unfocusedColor)
|
|
|
|
|
2020-07-04 16:16:57 +08:00
|
|
|
gomu.App.SetFocus(nextChild.(tview.Primitive))
|
2020-06-19 16:29:51 +08:00
|
|
|
nextChild.SetBorderColor(focusedColor)
|
|
|
|
nextChild.SetTitleColor(focusedColor)
|
|
|
|
|
2020-06-25 20:18:35 +08:00
|
|
|
return nextChild
|
2020-06-19 16:29:51 +08:00
|
|
|
}
|
|
|
|
}
|
2020-06-26 17:09:15 +08:00
|
|
|
|
|
|
|
first := childrens[0]
|
2020-06-25 20:18:35 +08:00
|
|
|
|
2020-07-03 00:50:18 +08:00
|
|
|
if !anyChildHasFocus {
|
2020-06-19 16:42:30 +08:00
|
|
|
|
2020-07-04 16:16:57 +08:00
|
|
|
gomu.App.SetFocus(first.(tview.Primitive))
|
2020-06-25 20:18:35 +08:00
|
|
|
first.SetBorderColor(focusedColor)
|
|
|
|
first.SetTitleColor(focusedColor)
|
|
|
|
|
2020-06-19 16:29:51 +08:00
|
|
|
}
|
|
|
|
|
2020-06-25 20:18:35 +08:00
|
|
|
return first
|
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
|
2020-07-04 16:16:57 +08:00
|
|
|
func Layout(gomu *Gomu) *tview.Flex {
|
2020-07-03 00:50:18 +08:00
|
|
|
|
|
|
|
flex := tview.NewFlex().
|
2020-07-04 16:16:57 +08:00
|
|
|
AddItem(gomu.Playlist, 0, 1, false).
|
2020-07-03 00:50:18 +08:00
|
|
|
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
|
2020-07-04 16:16:57 +08:00
|
|
|
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
|
|
|
|
|
|
|
|
}
|