175b694a4d
Searching the Global Database although is enough but I have felt a need to have a quick and fast search option to search the current buffer. Buffer Search is also one of the views It can be only turned on if the File Browser has focus. ( Thinking of making it global ). The Searching is done through the fuzzy module. FileNode now implements the Source Interface. The Changed Function of the Search Bar checks for text changes and then modifies the Matches Variable which is used by the Update Function to Draw the Results. The Results have the Matching Characters Highlighted Differently. Maximum of 15 results are displayed to avoid lag. Upon Selecting the Result through the Search Bar navigation is possible and selection of the item is done the same way it works for file Browser. After Selection the Focus is returned Back to the File Browser. For The Tracks only the title is used for searching.
333 lines
8.7 KiB
Go
333 lines
8.7 KiB
Go
package main
|
|
|
|
import (
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/aditya-K2/gomp/cache"
|
|
"github.com/aditya-K2/gomp/client"
|
|
"github.com/aditya-K2/gomp/config"
|
|
"github.com/aditya-K2/gomp/render"
|
|
"github.com/aditya-K2/gomp/ui"
|
|
"github.com/aditya-K2/gomp/ui/notify"
|
|
"github.com/aditya-K2/gomp/utils"
|
|
|
|
"github.com/aditya-K2/fuzzy"
|
|
"github.com/fhs/gompd/mpd"
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
func main() {
|
|
config.ReadConfig()
|
|
var mpdConnectionError error
|
|
CONN, mpdConnectionError := mpd.Dial("tcp", "localhost:"+viper.GetString("MPD_PORT"))
|
|
if mpdConnectionError != nil {
|
|
panic(mpdConnectionError)
|
|
}
|
|
defer CONN.Close()
|
|
|
|
ui.GenerateFocusMap()
|
|
|
|
client.SetConnection(CONN)
|
|
ui.SetConnection(CONN)
|
|
render.SetConnection(CONN)
|
|
|
|
cache.SetCacheDir(viper.GetString("CACHE_DIR"))
|
|
|
|
Renderer := render.NewRenderer()
|
|
// Connecting the Renderer to the Main UI
|
|
ui.ConnectRenderer(Renderer)
|
|
|
|
c, _ := CONN.CurrentSong()
|
|
if len(c) != 0 {
|
|
Renderer.Start(c["file"])
|
|
} else {
|
|
Renderer.Start("stop")
|
|
}
|
|
|
|
UI := ui.NewApplication()
|
|
|
|
// Connecting the Notification Server to the Main UI
|
|
notify.ConnectUI(UI)
|
|
|
|
fileMap, err := CONN.GetFiles()
|
|
|
|
// Generating the Directory Tree for File Navigation.
|
|
dirTree := client.GenerateDirectoryTree(fileMap)
|
|
|
|
// Default View upon Opening is of Playlist.
|
|
client.UpdatePlaylist(UI.ExpandedView)
|
|
|
|
_v, _ := CONN.Status()
|
|
// Setting Volume, Random and Repeat Values
|
|
Volume, _ := strconv.ParseInt(_v["volume"], 10, 64)
|
|
Random, _ := strconv.ParseBool(_v["random"])
|
|
Repeat, _ := strconv.ParseBool(_v["repeat"])
|
|
|
|
ArtistTree, err := client.GenerateArtistTree()
|
|
|
|
// Used for Fuzzy Searching
|
|
ArtistTreeContent := utils.ConvertToArray(ArtistTree)
|
|
|
|
Notify := notify.NewNotificationServer()
|
|
Notify.Start()
|
|
|
|
// Connecting Notification Server to Client and Rendering Module so that they can send Notifications
|
|
client.SetNotificationServer(Notify)
|
|
render.SetNotificationServer(Notify)
|
|
|
|
// This is the Slice that is used to Display Content in the SearchView
|
|
var SearchContentSlice []interface{}
|
|
var Matches fuzzy.Matches
|
|
|
|
// This Function Is Responsible for Changing the Focus it uses the Focus Map and Based on it Chooses
|
|
// the Draw Function
|
|
UI.ExpandedView.SetDrawFunc(func(s tcell.Screen, x, y, width, height int) (int, int, int, int) {
|
|
if ui.HasFocus("Playlist") {
|
|
client.UpdatePlaylist(UI.ExpandedView)
|
|
} else if ui.HasFocus("SearchView") {
|
|
client.UpdateSearchView(UI.ExpandedView, SearchContentSlice)
|
|
} else if ui.HasFocus("FileBrowser") {
|
|
client.Update(dirTree.Children, UI.ExpandedView)
|
|
} else if ui.HasFocus("BuffSearchView") {
|
|
client.UpdateBuffSearchView(UI.ExpandedView, Matches, dirTree.Children)
|
|
}
|
|
return UI.ExpandedView.GetInnerRect()
|
|
})
|
|
|
|
// Function Maps is used For Mapping Keys According to the Value mapped to the Key the respective Function is called
|
|
// For e.g. in the config if the User Maps T to togglePlayBack then whenever in the input handler the T is received
|
|
// the respective function in this case togglePlayBack is called.
|
|
var FuncMap = map[string]func(){
|
|
"showChildrenContent": func() {
|
|
if ui.HasFocus("FileBrowser") {
|
|
r, _ := UI.ExpandedView.GetSelection()
|
|
ui.SetFocus("FileBrowser")
|
|
if len(dirTree.Children[r].Children) == 0 {
|
|
id, _ := CONN.AddId(dirTree.Children[r].AbsolutePath, -1)
|
|
CONN.PlayId(id)
|
|
} else {
|
|
client.Update(dirTree.Children[r].Children, UI.ExpandedView)
|
|
dirTree = &dirTree.Children[r]
|
|
UI.ExpandedView.Select(0, 0)
|
|
}
|
|
} else if ui.HasFocus("Playlist") {
|
|
r, _ := UI.ExpandedView.GetSelection()
|
|
CONN.Play(r)
|
|
} else if ui.HasFocus("SearchView") {
|
|
r, _ := UI.ExpandedView.GetSelection()
|
|
client.AddToPlaylist(SearchContentSlice[r], true)
|
|
} else if ui.HasFocus("BuffSearchView") {
|
|
r, _ := UI.ExpandedView.GetSelection()
|
|
ui.SetFocus("FileBrowser")
|
|
if len(dirTree.Children[r].Children) == 0 {
|
|
id, _ := CONN.AddId(dirTree.Children[Matches[r].Index].AbsolutePath, -1)
|
|
CONN.PlayId(id)
|
|
} else {
|
|
client.Update(dirTree.Children[Matches[r].Index].Children, UI.ExpandedView)
|
|
dirTree = &dirTree.Children[Matches[r].Index]
|
|
}
|
|
UI.SearchBar.SetText("")
|
|
// Resetting Matches
|
|
Matches = nil
|
|
}
|
|
},
|
|
"togglePlayBack": func() {
|
|
client.TogglePlayBack()
|
|
},
|
|
"showParentContent": func() {
|
|
if ui.HasFocus("FileBrowser") {
|
|
if dirTree.Parent != nil {
|
|
client.Update(dirTree.Parent.Children, UI.ExpandedView)
|
|
dirTree = dirTree.Parent
|
|
}
|
|
}
|
|
},
|
|
"nextSong": func() {
|
|
CONN.Next()
|
|
},
|
|
"clearPlaylist": func() {
|
|
CONN.Clear()
|
|
Notify.Send("Playlist Cleared")
|
|
},
|
|
"previousSong": func() {
|
|
CONN.Previous()
|
|
},
|
|
"addToPlaylist": func() {
|
|
if ui.HasFocus("FileBrowser") {
|
|
r, _ := UI.ExpandedView.GetSelection()
|
|
CONN.Add(dirTree.Children[r].AbsolutePath)
|
|
} else if ui.HasFocus("SearchView") {
|
|
r, _ := UI.ExpandedView.GetSelection()
|
|
client.AddToPlaylist(SearchContentSlice[r], false)
|
|
}
|
|
},
|
|
"toggleRandom": func() {
|
|
err := CONN.Random(!Random)
|
|
if err == nil {
|
|
Random = !Random
|
|
}
|
|
},
|
|
"toggleRepeat": func() {
|
|
err := CONN.Repeat(!Repeat)
|
|
if err == nil {
|
|
Repeat = !Repeat
|
|
}
|
|
},
|
|
"decreaseVolume": func() {
|
|
if Volume <= 0 {
|
|
Volume = 0
|
|
} else {
|
|
Volume -= 10
|
|
}
|
|
CONN.SetVolume(int(Volume))
|
|
},
|
|
"increaseVolume": func() {
|
|
if Volume >= 100 {
|
|
Volume = 100
|
|
} else {
|
|
Volume += 10
|
|
}
|
|
CONN.SetVolume(int(Volume))
|
|
},
|
|
"navigateToFiles": func() {
|
|
ui.SetFocus("FileBrowser")
|
|
UI.Navbar.Select(1, 0)
|
|
client.Update(dirTree.Children, UI.ExpandedView)
|
|
},
|
|
"navigateToPlaylist": func() {
|
|
ui.SetFocus("Playlist")
|
|
UI.Navbar.Select(0, 0)
|
|
client.UpdatePlaylist(UI.ExpandedView)
|
|
},
|
|
"navigateToMostPlayed": func() {
|
|
UI.Navbar.Select(2, 0)
|
|
},
|
|
"navigateToSearch": func() {
|
|
ui.SetFocus("SearchView")
|
|
UI.Navbar.Select(3, 0)
|
|
},
|
|
"quit": func() {
|
|
if ui.HasFocus("BuffSearchView") {
|
|
ui.SetFocus("FileBrowser")
|
|
UI.SearchBar.SetText("")
|
|
Matches = nil
|
|
} else {
|
|
UI.App.Stop()
|
|
}
|
|
},
|
|
"stop": func() {
|
|
CONN.Stop()
|
|
Notify.Send("Playback Stopped")
|
|
},
|
|
"updateDB": func() {
|
|
_, err = CONN.Update("")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
Notify.Send("Database Updated")
|
|
},
|
|
"deleteSongFromPlaylist": func() {
|
|
if ui.HasFocus("Playlist") {
|
|
r, _ := UI.ExpandedView.GetSelection()
|
|
CONN.Delete(r, -1)
|
|
}
|
|
},
|
|
"FocusSearch": func() {
|
|
UI.App.SetFocus(UI.SearchBar)
|
|
},
|
|
"FocusBuffSearch": func() {
|
|
if ui.HasFocus("FileBrowser") || ui.HasFocus("BuffSearchView") {
|
|
ui.SetFocus("BuffSearchView")
|
|
UI.App.SetFocus(UI.SearchBar)
|
|
}
|
|
},
|
|
}
|
|
|
|
// Generating the Key Map Based on the Function Map Here Basically the Values will be flipped
|
|
// In the config if togglePlayBack is mapped to [ T , P, SPACE ] then here Basically we will receive a map
|
|
// for each event T, P, SPACE mapped to the same function togglePlayBack
|
|
config.GenerateKeyMap(FuncMap)
|
|
|
|
UI.SearchBar.SetAutocompleteFunc(func(c string) []string {
|
|
if ui.HasFocus("BuffSearchView") {
|
|
return nil
|
|
} else {
|
|
if c != "" && c != " " && c != " " {
|
|
_, _, w, _ := UI.SearchBar.GetRect()
|
|
matches := fuzzy.Find(c, ArtistTreeContent)
|
|
var suggestions []string
|
|
for i, match := range matches {
|
|
if i == 10 {
|
|
break
|
|
}
|
|
suggestions = append(suggestions, utils.GetFormattedString(match.Str, w-2))
|
|
}
|
|
return suggestions
|
|
} else {
|
|
return make([]string, 0)
|
|
}
|
|
}
|
|
})
|
|
|
|
// Input Handler
|
|
UI.ExpandedView.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey {
|
|
if val, ok := config.KEY_MAP[int(e.Rune())]; ok {
|
|
FuncMap[val]()
|
|
return nil
|
|
} else {
|
|
return e
|
|
}
|
|
})
|
|
|
|
UI.SearchBar.SetDoneFunc(func(e tcell.Key) {
|
|
if e == tcell.KeyEnter {
|
|
UI.ExpandedView.Select(0, 0)
|
|
if ui.HasFocus("BuffSearchView") {
|
|
UI.App.SetFocus(UI.ExpandedView)
|
|
} else {
|
|
ui.SetFocus("SearchView")
|
|
SearchContentSlice = nil
|
|
SearchContentSlice, err = client.GenerateContentSlice(UI.SearchBar.GetText())
|
|
if err != nil {
|
|
Notify.Send("Could Not Retrieve the Results")
|
|
} else {
|
|
UI.SearchBar.SetText("")
|
|
UI.App.SetFocus(UI.ExpandedView)
|
|
UI.Navbar.Select(3, 0)
|
|
}
|
|
}
|
|
}
|
|
if e == tcell.KeyEscape {
|
|
if ui.HasFocus("SearchView") {
|
|
ui.FocusMap["SearchView"] = false
|
|
} else if ui.HasFocus("BuffSearchView") {
|
|
ui.SetFocus("FileBrowser")
|
|
Matches = nil
|
|
}
|
|
UI.SearchBar.SetText("")
|
|
UI.App.SetFocus(UI.ExpandedView)
|
|
}
|
|
})
|
|
|
|
UI.SearchBar.SetChangedFunc(func(text string) {
|
|
if ui.HasFocus("BuffSearchView") {
|
|
var f client.FileNodes = dirTree.Children
|
|
Matches = fuzzy.FindFrom(text, f)
|
|
client.UpdateBuffSearchView(UI.ExpandedView, Matches, dirTree.Children)
|
|
}
|
|
})
|
|
|
|
go func() {
|
|
for {
|
|
UI.App.Draw()
|
|
time.Sleep(time.Second)
|
|
}
|
|
}()
|
|
|
|
if err := UI.App.Run(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|