From 175b694a4da619f764f73edaff70e7731987a590 Mon Sep 17 00:00:00 2001 From: aditya-K2 Date: Sun, 26 Dec 2021 00:18:23 +0530 Subject: [PATCH 01/10] Implementing Simple Buffer Searching 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. --- client/client.go | 83 ------------------------------- client/files.go | 21 +++++++- client/updateView.go | 113 +++++++++++++++++++++++++++++++++++++++++++ main.go | 109 ++++++++++++++++++++++++++++++----------- ui/focus.go | 1 + utils/utils.go | 35 ++++++++++++++ 6 files changed, 249 insertions(+), 113 deletions(-) create mode 100644 client/updateView.go diff --git a/client/client.go b/client/client.go index fece67c..2c5d72b 100644 --- a/client/client.go +++ b/client/client.go @@ -7,9 +7,6 @@ import ( "github.com/fhs/gompd/mpd" "strings" - - "github.com/aditya-K2/gomp/utils" - "github.com/aditya-K2/tview" ) var ( @@ -39,22 +36,6 @@ func TogglePlayBack() error { return err } -func UpdatePlaylist(inputTable *tview.Table) { - _playlistAttr, _ := CONN.PlaylistInfo(-1, -1) - - inputTable.Clear() - for i, j := range _playlistAttr { - _, _, w, _ := inputTable.GetInnerRect() - if j["Title"] == "" || j["Artist"] == "" || j["Album"] == "" { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(j["file"], w/3))) - } else { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+j["Title"], w/3))) - inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+j["Artist"], w/3))) - inputTable.SetCell(i, 2, tview.NewTableCell("[yellow]"+j["Album"])) - } - } -} - // The GenerateContentSlice returns a slice of the content to be displayed on the Search View. The Slice is generated // because the random nature of maps as they return values randomly hence the draw function keeps changing the order // in which the results appear. @@ -99,70 +80,6 @@ func GenerateContentSlice(selectedSuggestion string) ([]interface{}, error) { return ContentSlice, nil } -// UpdateSearchView as the name suggests Updates the Search View the idea is to basically keep a fourth option called -// Search in the Navigation bar which will render things from a global ContentSlice at least in the context of the main -// function this will also help in persisting the Search Results. -func UpdateSearchView(inputTable *tview.Table, c []interface{}) { - inputTable.Clear() - _, _, width, _ := inputTable.GetInnerRect() - for i, content := range c { - switch content.(type) { - case [3]string: - { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+content.([3]string)[0], width/3))) - inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+content.([3]string)[1], width/3))) - inputTable.SetCell(i, 2, tview.NewTableCell(utils.GetFormattedString("[yellow]"+content.([3]string)[2], width/3))) - } - case [2]string: - { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+content.([2]string)[0], width/3))) - inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+content.([2]string)[1], width/3))) - } - case string: - { - b := content.(string) - if !strings.HasPrefix(b, WHITE_AND_BOLD) { - inputTable.SetCell(i, 0, tview.NewTableCell("[green]"+content.(string))) - } else { - inputTable.SetCell(i, 0, tview.NewTableCell(content.(string)).SetSelectable(false)) - } - } - } - } -} - -func Update(f []FileNode, inputTable *tview.Table) { - inputTable.Clear() - for i, j := range f { - if len(j.Children) == 0 { - _songAttributes, err := CONN.ListAllInfo(j.AbsolutePath) - if err == nil && _songAttributes[0]["Title"] != "" { - _, _, w, _ := inputTable.GetInnerRect() - inputTable.SetCell(i, 0, - tview.NewTableCell("[green]"+utils.GetFormattedString(_songAttributes[0]["Title"], w/3)). - SetAlign(tview.AlignLeft)) - - inputTable.SetCell(i, 1, - tview.NewTableCell("[magenta]"+utils.GetFormattedString(_songAttributes[0]["Artist"], w/3)). - SetAlign(tview.AlignLeft)) - - inputTable.SetCell(i, 2, - tview.NewTableCell("[yellow]"+_songAttributes[0]["Album"]). - SetAlign(tview.AlignLeft)) - - } else if _songAttributes[0]["Title"] == "" { - inputTable.SetCell(i, 0, - tview.NewTableCell("[blue]"+j.Path). - SetAlign(tview.AlignLeft)) - } - } else { - inputTable.SetCell(i, 0, - tview.NewTableCell("[yellow::b]"+j.Path). - SetAlign(tview.AlignLeft)) - } - } -} - // GenerateArtistTree Artist Tree is a map of Artist to their Album Map // Album Tree is a map of the tracks in that particular album. func GenerateArtistTree() (map[string]map[string]map[string]string, error) { diff --git a/client/files.go b/client/files.go index 71cac40..aeadd35 100644 --- a/client/files.go +++ b/client/files.go @@ -6,12 +6,31 @@ import ( ) type FileNode struct { - Children []FileNode + Children []FileNode Path string Parent *FileNode AbsolutePath string } +// Source Interface For Fuzzy Searching. +type FileNodes []FileNode + +func (f FileNodes) String(i int) string { + if len(f[i].Children) == 0 { + _s, err := CONN.ListAllInfo(f[i].AbsolutePath) + if err != nil { + NotificationServer.Send(fmt.Sprintf("Could Not Get Information About the Node %s", f[i].Path)) + return f[i].Path + } + return _s[0]["Title"] + } + return f[i].Path +} + +func (f FileNodes) Len() int { + return len(f) +} + func (f *FileNode) AddChildren(path string) { if f.Path != "" { f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + "/" + path}) diff --git a/client/updateView.go b/client/updateView.go new file mode 100644 index 0000000..8a5000b --- /dev/null +++ b/client/updateView.go @@ -0,0 +1,113 @@ +package client + +import ( + "fmt" + "strings" + + "github.com/aditya-K2/fuzzy" + "github.com/aditya-K2/gomp/utils" + "github.com/aditya-K2/tview" +) + +func UpdateBuffSearchView(inputTable *tview.Table, m fuzzy.Matches, f []FileNode) { + inputTable.Clear() + if m == nil || len(m) == 0 { + Update(f, inputTable) + } else { + for k, v := range m { + if len(f[v.Index].Children) != 0 { + inputTable.SetCellSimple(k, 0, utils.GetMatchedString(f[v.Index].Path, "#0000ff", "yellow", v.MatchedIndexes)) + } else { + _s, err := CONN.ListAllInfo(f[v.Index].AbsolutePath) + if err != nil { + NotificationServer.Send(fmt.Sprintf("Could Not Add %s to the Table", f[v.Index].Path)) + } else { + inputTable.SetCellSimple(k, 0, utils.GetMatchedString(_s[0]["Title"], "#fbff00", "green", v.MatchedIndexes)) + } + } + if k == 15 { + break + } + } + } +} + +func UpdatePlaylist(inputTable *tview.Table) { + _playlistAttr, _ := CONN.PlaylistInfo(-1, -1) + + inputTable.Clear() + for i, j := range _playlistAttr { + _, _, w, _ := inputTable.GetInnerRect() + if j["Title"] == "" || j["Artist"] == "" || j["Album"] == "" { + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(j["file"], w/3))) + } else { + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+j["Title"], w/3))) + inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+j["Artist"], w/3))) + inputTable.SetCell(i, 2, tview.NewTableCell("[yellow]"+j["Album"])) + } + } +} + +// UpdateSearchView as the name suggests Updates the Search View the idea is to basically keep a fourth option called +// Search in the Navigation bar which will render things from a global ContentSlice at least in the context of the main +// function this will also help in persisting the Search Results. +func UpdateSearchView(inputTable *tview.Table, c []interface{}) { + inputTable.Clear() + _, _, width, _ := inputTable.GetInnerRect() + for i, content := range c { + switch content.(type) { + case [3]string: + { + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+content.([3]string)[0], width/3))) + inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+content.([3]string)[1], width/3))) + inputTable.SetCell(i, 2, tview.NewTableCell(utils.GetFormattedString("[yellow]"+content.([3]string)[2], width/3))) + } + case [2]string: + { + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+content.([2]string)[0], width/3))) + inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+content.([2]string)[1], width/3))) + } + case string: + { + b := content.(string) + if !strings.HasPrefix(b, WHITE_AND_BOLD) { + inputTable.SetCell(i, 0, tview.NewTableCell("[green]"+content.(string))) + } else { + inputTable.SetCell(i, 0, tview.NewTableCell(content.(string)).SetSelectable(false)) + } + } + } + } +} + +func Update(f []FileNode, inputTable *tview.Table) { + inputTable.Clear() + for i, j := range f { + if len(j.Children) == 0 { + _songAttributes, err := CONN.ListAllInfo(j.AbsolutePath) + if err == nil && _songAttributes[0]["Title"] != "" { + _, _, w, _ := inputTable.GetInnerRect() + inputTable.SetCell(i, 0, + tview.NewTableCell("[green]"+utils.GetFormattedString(_songAttributes[0]["Title"], w/3)). + SetAlign(tview.AlignLeft)) + + inputTable.SetCell(i, 1, + tview.NewTableCell("[magenta]"+utils.GetFormattedString(_songAttributes[0]["Artist"], w/3)). + SetAlign(tview.AlignLeft)) + + inputTable.SetCell(i, 2, + tview.NewTableCell("[yellow]"+_songAttributes[0]["Album"]). + SetAlign(tview.AlignLeft)) + + } else if _songAttributes[0]["Title"] == "" { + inputTable.SetCell(i, 0, + tview.NewTableCell("[blue]"+j.Path). + SetAlign(tview.AlignLeft)) + } + } else { + inputTable.SetCell(i, 0, + tview.NewTableCell("[yellow::b]"+j.Path). + SetAlign(tview.AlignLeft)) + } + } +} diff --git a/main.go b/main.go index 5ca3447..bb2eb03 100644 --- a/main.go +++ b/main.go @@ -4,17 +4,15 @@ import ( "strconv" "time" - "github.com/aditya-K2/gomp/ui/notify" - + "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/client" + "github.com/aditya-K2/gomp/ui/notify" "github.com/aditya-K2/gomp/utils" "github.com/aditya-K2/fuzzy" - "github.com/aditya-K2/gomp/cache" - "github.com/aditya-K2/gomp/config" "github.com/fhs/gompd/mpd" "github.com/gdamore/tcell/v2" "github.com/spf13/viper" @@ -81,6 +79,7 @@ func main() { // 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 @@ -91,6 +90,8 @@ func main() { 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() }) @@ -100,20 +101,36 @@ func main() { // the respective function in this case togglePlayBack is called. var FuncMap = map[string]func(){ "showChildrenContent": func() { - r, _ := UI.ExpandedView.GetSelection() 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() { @@ -192,7 +209,13 @@ func main() { UI.Navbar.Select(3, 0) }, "quit": func() { - UI.App.Stop() + if ui.HasFocus("BuffSearchView") { + ui.SetFocus("FileBrowser") + UI.SearchBar.SetText("") + Matches = nil + } else { + UI.App.Stop() + } }, "stop": func() { CONN.Stop() @@ -214,6 +237,12 @@ func main() { "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 @@ -222,19 +251,23 @@ func main() { config.GenerateKeyMap(FuncMap) UI.SearchBar.SetAutocompleteFunc(func(c string) []string { - 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 + if ui.HasFocus("BuffSearchView") { + return nil } else { - return make([]string, 0) + 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) + } } }) @@ -251,23 +284,41 @@ func main() { UI.SearchBar.SetDoneFunc(func(e tcell.Key) { if e == tcell.KeyEnter { UI.ExpandedView.Select(0, 0) - 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("") + if ui.HasFocus("BuffSearchView") { UI.App.SetFocus(UI.ExpandedView) - UI.Navbar.Select(3, 0) + } 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 { - ui.FocusMap["SearchView"] = false + 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() diff --git a/ui/focus.go b/ui/focus.go index b71c377..2251b85 100644 --- a/ui/focus.go +++ b/ui/focus.go @@ -10,6 +10,7 @@ func GenerateFocusMap() { FocusMap["Playlist"] = true FocusMap["FileBrowser"] = false FocusMap["SearchView"] = false + FocusMap["BuffSearchView"] = false } func HasFocus(s string) bool { diff --git a/utils/utils.go b/utils/utils.go index ee88706..23fdc29 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,6 +1,7 @@ package utils import ( + "fmt" "io/ioutil" "strconv" "strings" @@ -136,3 +137,37 @@ func CheckDirectoryFmt(path string) string { return path + "/" } } + +func GetMatchedString(s string, color string, nulcol string, matchedIndexes []int) string { + // The indexes that we will receive from the matchedIndexes are always sorted so we have to just + // add the color string at + // `indexValue + ( len(colorString) * k )` + // where k is the index of the indexValue in the matchedIndexes slice + // and we will need to also reset the colors, For that we check if the next indexValue in the matchedIndexes for + // the current indexValue is not the consecutive value ( v + 1 ) if yes ( is not consecutive ) then we add the reset + // color string at the k + 1 index in the string. + // for e.g. + // if we have the following matchedIndexes slice + // []int{ 1, 3, 4, 6} + // During the First Iteration matchedIndexes[k] = 1 and and matchedIndexes[k+1] are not consecutive so the nulcol + // string will be added to the matchedIndexes[k] + 1 index of the string + // During the Second Iteration as 3, 4 are consecutive the nulcol will be skipped. + color = fmt.Sprintf("[%s:-:bi]", color) + nulcol = fmt.Sprintf("[%s:-:b]", nulcol) + nulc := 0 + for k := range matchedIndexes { + s = InsertAt(s, color, matchedIndexes[k]+(len(color)*k)+nulc) + if k < len(matchedIndexes)-1 && matchedIndexes[k]-matchedIndexes[k+1] != 1 { + s = InsertAt(s, nulcol, (matchedIndexes[k]+1)+(len(color)*(k+1))+nulc) + nulc += len(nulcol) + } + if k == len(matchedIndexes)-1 { + s = InsertAt(s, nulcol, ((matchedIndexes[len(matchedIndexes)-1] + 1) + + (len(matchedIndexes) * len(color)) + + (len(nulcol) * (len(matchedIndexes) - 1)))) + } + } + // Adding the Nulcol at the Start + s = nulcol + s + return s +} From 7b35d30ef765374e553ac3490ce5168c65a9a66d Mon Sep 17 00:00:00 2001 From: aditya-K2 Date: Sun, 26 Dec 2021 14:04:13 +0530 Subject: [PATCH 02/10] Changed Default Key Mappings and updated The Documentation --- config/kMap.go | 3 ++- docs/index.md | 45 +++++++++++++++++++++++---------------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/config/kMap.go b/config/kMap.go index fa29abd..ad949e4 100644 --- a/config/kMap.go +++ b/config/kMap.go @@ -48,7 +48,8 @@ var ( 115: "stop", 117: "updateDB", 100: "deleteSongFromPlaylist", - 47: "FocusSearch", + 63: "FocusSearch", + 47: "FocusBuffSearch", } ) diff --git a/docs/index.md b/docs/index.md index 25382cd..c385667 100644 --- a/docs/index.md +++ b/docs/index.md @@ -147,28 +147,29 @@ togglePlayBack : [ "p", "TAB", "[" ] # using the quotes is neccessary. Following functions are provided : -| Functions | -|------------------------------------| -| showChildrenContent | -| togglePlayBack | -| showParentContent | -| nextSong | -| clearPlaylist | -| previousSong | -| addToPlaylist | -| toggleRandom | -| toggleRepeat | -| decreaseVolume | -| increaseVolume | -| navigateToFiles | -| navigateToPlaylist | -| navigateToMostPlayed | -| navigateToSearch | -| quit | -| stop | -| updateDB | -| deleteSongFromPlaylist | -| FocusSearch | +| Functions | Default Key Mapping | +|------------------------------------|---------------------| +| showChildrenContent | l | +| togglePlayBack | p | +| showParentContent | h | +| nextSong | n | +| clearPlaylist | c | +| previousSong | N | +| addToPlaylist | a | +| toggleRandom | z | +| toggleRepeat | r | +| decreaseVolume | - | +| increaseVolume | + | +| navigateToFiles | 2 | +| navigateToPlaylist | 1 | +| navigateToMostPlayed | 3 | +| navigateToSearch | 4 | +| quit | q | +| stop | s | +| updateDB | u | +| deleteSongFromPlaylist | d | +| FocusSearch | ? | +| FocusBuffSearch | / | ## Getting Album Art from [LastFm API](https://www.last.fm/api) From a8ae5fb42615341da377c428744078359422dce7 Mon Sep 17 00:00:00 2001 From: aditya-K2 Date: Sun, 26 Dec 2021 19:23:58 +0530 Subject: [PATCH 03/10] Adding more sensible defaults. 1. After Selection during navigating the folder can be added to the playlist now. 2. Also Binded Escape to quit the BuffSearchView --- main.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/main.go b/main.go index bb2eb03..62ae21f 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "strconv" "time" @@ -161,6 +162,16 @@ func main() { } else if ui.HasFocus("SearchView") { r, _ := UI.ExpandedView.GetSelection() client.AddToPlaylist(SearchContentSlice[r], false) + } else if ui.HasFocus("BuffSearchView") { + r, _ := UI.ExpandedView.GetSelection() + ui.SetFocus("FileBrowser") + err := CONN.Add(dirTree.Children[Matches[r].Index].AbsolutePath) + if err != nil { + Notify.Send(fmt.Sprintf("Could Not Add URI %s to the Playlist", dirTree.Children[Matches[r].Index].Path)) + } else { + Notify.Send(fmt.Sprintf("URI Added %s to the Playlist", dirTree.Children[Matches[r].Index].Path)) + } + ui.SetFocus("BuffSearchView") } }, "toggleRandom": func() { @@ -311,6 +322,16 @@ func main() { } }) + UI.ExpandedView.SetDoneFunc(func(e tcell.Key) { + if e == tcell.KeyEscape { + if ui.HasFocus("BuffSearchView") { + ui.SetFocus("FileBrowser") + UI.SearchBar.SetText("") + Matches = nil + } + } + }) + UI.SearchBar.SetChangedFunc(func(text string) { if ui.HasFocus("BuffSearchView") { var f client.FileNodes = dirTree.Children From 09297a49748d4570b3f32004ba6e054a91799463 Mon Sep 17 00:00:00 2001 From: aditya-K2 Date: Tue, 28 Dec 2021 10:32:48 +0530 Subject: [PATCH 04/10] Adding A new Field to the FileNode -> `Title` Previously During Searching the Connection with mpd client was utilised to get the title for the files this was slowing the search with large number of files. Now after adding the Title field to the struct the Field is accessed instead of querying the server this has lead to faster searches. [[ Please Note the Title of a Folder would be the last accessed track from the FileMap. ]] --- client/files.go | 24 +++++++++++------------- client/updateView.go | 8 +------- main.go | 2 +- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/client/files.go b/client/files.go index aeadd35..7e2f770 100644 --- a/client/files.go +++ b/client/files.go @@ -3,6 +3,8 @@ package client import ( "fmt" "strings" + + "github.com/fhs/gompd/mpd" ) type FileNode struct { @@ -10,6 +12,7 @@ type FileNode struct { Path string Parent *FileNode AbsolutePath string + Title string } // Source Interface For Fuzzy Searching. @@ -17,12 +20,7 @@ type FileNodes []FileNode func (f FileNodes) String(i int) string { if len(f[i].Children) == 0 { - _s, err := CONN.ListAllInfo(f[i].AbsolutePath) - if err != nil { - NotificationServer.Send(fmt.Sprintf("Could Not Get Information About the Node %s", f[i].Path)) - return f[i].Path - } - return _s[0]["Title"] + return f[i].Title } return f[i].Path } @@ -31,11 +29,11 @@ func (f FileNodes) Len() int { return len(f) } -func (f *FileNode) AddChildren(path string) { +func (f *FileNode) AddChildren(path string, title string) { if f.Path != "" { - f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + "/" + path}) + f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + "/" + path, Title: title}) } else { - f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + path}) + f.Children = append(f.Children, FileNode{Children: make([]FileNode, 0), Path: path, Parent: f, AbsolutePath: f.AbsolutePath + path, Title: title}) } } @@ -44,14 +42,14 @@ func (f *FileNode) AddChildNode(m FileNode) { f.Children = append(f.Children, m) } -func GenerateDirectoryTree(path []string) *FileNode { +func GenerateDirectoryTree(path []mpd.Attrs) *FileNode { var head *FileNode = new(FileNode) var head1 *FileNode = head for i := range path { - sepPaths := strings.Split(path[i], "/") + sepPaths := strings.Split(path[i]["file"], "/") for j := range sepPaths { if len(head.Children) == 0 { - head.AddChildren(sepPaths[j]) + head.AddChildren(sepPaths[j], path[i]["Title"]) head = &(head.Children[len(head.Children)-1]) } else { var headIsChanged = false @@ -63,7 +61,7 @@ func GenerateDirectoryTree(path []string) *FileNode { } } if !headIsChanged { - head.AddChildren(sepPaths[j]) + head.AddChildren(sepPaths[j], path[i]["Title"]) head = &(head.Children[len(head.Children)-1]) } } diff --git a/client/updateView.go b/client/updateView.go index 8a5000b..d3c59b7 100644 --- a/client/updateView.go +++ b/client/updateView.go @@ -1,7 +1,6 @@ package client import ( - "fmt" "strings" "github.com/aditya-K2/fuzzy" @@ -18,12 +17,7 @@ func UpdateBuffSearchView(inputTable *tview.Table, m fuzzy.Matches, f []FileNode if len(f[v.Index].Children) != 0 { inputTable.SetCellSimple(k, 0, utils.GetMatchedString(f[v.Index].Path, "#0000ff", "yellow", v.MatchedIndexes)) } else { - _s, err := CONN.ListAllInfo(f[v.Index].AbsolutePath) - if err != nil { - NotificationServer.Send(fmt.Sprintf("Could Not Add %s to the Table", f[v.Index].Path)) - } else { - inputTable.SetCellSimple(k, 0, utils.GetMatchedString(_s[0]["Title"], "#fbff00", "green", v.MatchedIndexes)) - } + inputTable.SetCellSimple(k, 0, utils.GetMatchedString(f[v.Index].Title, "#fbff00", "green", v.MatchedIndexes)) } if k == 15 { break diff --git a/main.go b/main.go index 62ae21f..b25aeee 100644 --- a/main.go +++ b/main.go @@ -52,7 +52,7 @@ func main() { // Connecting the Notification Server to the Main UI notify.ConnectUI(UI) - fileMap, err := CONN.GetFiles() + fileMap, err := CONN.ListAllInfo("/") // Generating the Directory Tree for File Navigation. dirTree := client.GenerateDirectoryTree(fileMap) From 921ab9e8313d776c1e8cbd1b8c15855427d67bb3 Mon Sep 17 00:00:00 2001 From: aditya-K2 Date: Tue, 28 Dec 2021 22:31:52 +0530 Subject: [PATCH 05/10] Updated go.mod file --- go.mod | 2 +- go.sum | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 220e090..058689d 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/aditya-K2/gomp go 1.16 require ( - github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4 // indirect + github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4 github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c github.com/bogem/id3v2 v1.2.0 github.com/fhs/gompd v1.0.1 diff --git a/go.sum b/go.sum index fe56a24..e13bb7e 100644 --- a/go.sum +++ b/go.sum @@ -54,8 +54,6 @@ github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e/go.mod h1:uw9h2 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4 h1:GEy4yHiudZCZyhwhP/2IWkcHCSkuUv/A4vKgktkIRYE= github.com/aditya-K2/fuzzy v0.1.1-0.20211128173834-d0023b66cdd4/go.mod h1:82s+GWKOo176xBYRWstoAM6Fl5jpXNuZ1syuJvRwVN8= -github.com/aditya-K2/tview v0.0.0-20211115155623-217bcbdc952c h1:HE/P4zSd5GE7wdCicacdo5m2vZk6E7BSS5NOY00gaPM= -github.com/aditya-K2/tview v0.0.0-20211115155623-217bcbdc952c/go.mod h1:nPfBlFYx4SBcLlONif45KWw2mvEbRgP/nNCkH/dMhIQ= github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c h1:UG9OxyXccanOiC83FEonB3+iLYvA3aAYgiX1N7Vurm0= github.com/aditya-K2/tview v0.0.0-20211115161300-6b99c2c2658c/go.mod h1:nPfBlFYx4SBcLlONif45KWw2mvEbRgP/nNCkH/dMhIQ= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -219,6 +217,7 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= From f7c22833553e99634e032bd389eae6cf1311fd1c Mon Sep 17 00:00:00 2001 From: aditya-K2 Date: Wed, 29 Dec 2021 22:22:34 +0530 Subject: [PATCH 06/10] Update Highlighting Algorithm & Using Tcell Styles The Algorithm now only inserts the color string over a range i.e if 1, 2, 3 are matches then instead of adding individually at 1, 2, 3 it adds the color string at 1 and null color string at 3. Also Using tcell Styles for highlighting the table cells. --- .gitignore | 1 + client/updateView.go | 114 ++++++++++++++++++++++++++++++++++--------- utils/utils.go | 58 +++++++++++----------- 3 files changed, 121 insertions(+), 52 deletions(-) diff --git a/.gitignore b/.gitignore index 3a9e535..f031a60 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ gomp .idea *.jpg +e.go diff --git a/client/updateView.go b/client/updateView.go index d3c59b7..e9e63de 100644 --- a/client/updateView.go +++ b/client/updateView.go @@ -6,6 +6,7 @@ import ( "github.com/aditya-K2/fuzzy" "github.com/aditya-K2/gomp/utils" "github.com/aditya-K2/tview" + "github.com/gdamore/tcell/v2" ) func UpdateBuffSearchView(inputTable *tview.Table, m fuzzy.Matches, f []FileNode) { @@ -15,9 +16,19 @@ func UpdateBuffSearchView(inputTable *tview.Table, m fuzzy.Matches, f []FileNode } else { for k, v := range m { if len(f[v.Index].Children) != 0 { - inputTable.SetCellSimple(k, 0, utils.GetMatchedString(f[v.Index].Path, "#0000ff", "yellow", v.MatchedIndexes)) + inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(v.MatchedIndexes, f[v.Index].Path, "[#0000ff:-:bi]")). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorYellow). + Background(tcell.ColorBlack). + Bold(true))) } else { - inputTable.SetCellSimple(k, 0, utils.GetMatchedString(f[v.Index].Title, "#fbff00", "green", v.MatchedIndexes)) + inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(v.MatchedIndexes, f[v.Index].Title, "[#fbff00:-:bi]")). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorGreen). + Background(tcell.ColorBlack). + Bold(true))) } if k == 15 { break @@ -33,11 +44,29 @@ func UpdatePlaylist(inputTable *tview.Table) { for i, j := range _playlistAttr { _, _, w, _ := inputTable.GetInnerRect() if j["Title"] == "" || j["Artist"] == "" || j["Album"] == "" { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(j["file"], w/3))) + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(j["file"], w/3)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorBlue). + Background(tcell.ColorBlack). + Bold(true))) + } else { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+j["Title"], w/3))) - inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+j["Artist"], w/3))) - inputTable.SetCell(i, 2, tview.NewTableCell("[yellow]"+j["Album"])) + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(j["Title"], w/3)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorGreen). + Background(tcell.ColorBlack))) + inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString(j["Artist"], w/3)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorPurple). + Background(tcell.ColorBlack))) + inputTable.SetCell(i, 2, tview.NewTableCell(j["Album"]). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorYellow). + Background(tcell.ColorBlack))) } } } @@ -52,20 +81,44 @@ func UpdateSearchView(inputTable *tview.Table, c []interface{}) { switch content.(type) { case [3]string: { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+content.([3]string)[0], width/3))) - inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+content.([3]string)[1], width/3))) - inputTable.SetCell(i, 2, tview.NewTableCell(utils.GetFormattedString("[yellow]"+content.([3]string)[2], width/3))) + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(content.([3]string)[0], width/3)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorGreen). + Background(tcell.ColorBlack))) + inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString(content.([3]string)[1], width/3)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorPurple). + Background(tcell.ColorBlack))) + inputTable.SetCell(i, 2, tview.NewTableCell(utils.GetFormattedString(content.([3]string)[2], width/3)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorYellow). + Background(tcell.ColorBlack))) } case [2]string: { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString("[green]"+content.([2]string)[0], width/3))) - inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString("[magenta]"+content.([2]string)[1], width/3))) + inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(content.([2]string)[0], width/3)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorYellow). + Background(tcell.ColorBlack))) + inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString(content.([2]string)[1], width/3)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorPurple). + Background(tcell.ColorBlack))) } case string: { b := content.(string) if !strings.HasPrefix(b, WHITE_AND_BOLD) { - inputTable.SetCell(i, 0, tview.NewTableCell("[green]"+content.(string))) + inputTable.SetCell(i, 0, tview.NewTableCell(content.(string)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorPurple). + Background(tcell.ColorBlack))) } else { inputTable.SetCell(i, 0, tview.NewTableCell(content.(string)).SetSelectable(false)) } @@ -82,26 +135,43 @@ func Update(f []FileNode, inputTable *tview.Table) { if err == nil && _songAttributes[0]["Title"] != "" { _, _, w, _ := inputTable.GetInnerRect() inputTable.SetCell(i, 0, - tview.NewTableCell("[green]"+utils.GetFormattedString(_songAttributes[0]["Title"], w/3)). - SetAlign(tview.AlignLeft)) + tview.NewTableCell(utils.GetFormattedString(_songAttributes[0]["Title"], w/3)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorGreen). + Background(tcell.ColorBlack))) inputTable.SetCell(i, 1, - tview.NewTableCell("[magenta]"+utils.GetFormattedString(_songAttributes[0]["Artist"], w/3)). - SetAlign(tview.AlignLeft)) + tview.NewTableCell(utils.GetFormattedString(_songAttributes[0]["Artist"], w/3)). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorPurple). + Background(tcell.ColorBlack))) inputTable.SetCell(i, 2, - tview.NewTableCell("[yellow]"+_songAttributes[0]["Album"]). - SetAlign(tview.AlignLeft)) + tview.NewTableCell(_songAttributes[0]["Album"]). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorYellow). + Background(tcell.ColorBlack))) } else if _songAttributes[0]["Title"] == "" { inputTable.SetCell(i, 0, - tview.NewTableCell("[blue]"+j.Path). - SetAlign(tview.AlignLeft)) + tview.NewTableCell(j.Path). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorBlue). + Background(tcell.ColorBlack). + Bold(true))) } } else { inputTable.SetCell(i, 0, - tview.NewTableCell("[yellow::b]"+j.Path). - SetAlign(tview.AlignLeft)) + tview.NewTableCell(j.Path). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(tcell.ColorYellow). + Background(tcell.ColorBlack). + Bold(true))) } } } diff --git a/utils/utils.go b/utils/utils.go index 23fdc29..dc18e7f 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,7 +1,6 @@ package utils import ( - "fmt" "io/ioutil" "strconv" "strings" @@ -138,36 +137,35 @@ func CheckDirectoryFmt(path string) string { } } -func GetMatchedString(s string, color string, nulcol string, matchedIndexes []int) string { - // The indexes that we will receive from the matchedIndexes are always sorted so we have to just - // add the color string at - // `indexValue + ( len(colorString) * k )` - // where k is the index of the indexValue in the matchedIndexes slice - // and we will need to also reset the colors, For that we check if the next indexValue in the matchedIndexes for - // the current indexValue is not the consecutive value ( v + 1 ) if yes ( is not consecutive ) then we add the reset - // color string at the k + 1 index in the string. - // for e.g. - // if we have the following matchedIndexes slice - // []int{ 1, 3, 4, 6} - // During the First Iteration matchedIndexes[k] = 1 and and matchedIndexes[k+1] are not consecutive so the nulcol - // string will be added to the matchedIndexes[k] + 1 index of the string - // During the Second Iteration as 3, 4 are consecutive the nulcol will be skipped. - color = fmt.Sprintf("[%s:-:bi]", color) - nulcol = fmt.Sprintf("[%s:-:b]", nulcol) - nulc := 0 - for k := range matchedIndexes { - s = InsertAt(s, color, matchedIndexes[k]+(len(color)*k)+nulc) - if k < len(matchedIndexes)-1 && matchedIndexes[k]-matchedIndexes[k+1] != 1 { - s = InsertAt(s, nulcol, (matchedIndexes[k]+1)+(len(color)*(k+1))+nulc) - nulc += len(nulcol) - } - if k == len(matchedIndexes)-1 { - s = InsertAt(s, nulcol, ((matchedIndexes[len(matchedIndexes)-1] + 1) + - (len(matchedIndexes) * len(color)) + - (len(nulcol) * (len(matchedIndexes) - 1)))) +func GetMatchedString(a []int, s, color string) string { + // The Matches are sorted so we just have to traverse the Matches and if the two adjacent matches are not consecutive + // then we append the color string at the start + offset and the nulcol ( reset ) at end + offset + 1 and then reset + // start and end to a[k+1] for e.g if matches := []int{1, 2, 4, 5, 6, 9} then the start will be 1 and end will be 1 + // now until we reach `4` the value of end will change to `2` that means when we reach `4` the s string will be + // `O[yellow:-:-]ut[-:-:-]putString` after that until we reach the end will be changed and finally become `6` and the + // s string will be `O[yellow:-:-]ut[-:-:-]p[yellow:-:-]utS[-:-:-]tring` + // Please note that after around 45 simulatenously highlighted characters tview stops highlighting and the color + // sequences are rendered hope no one has that big of search query. + start := a[0] + end := a[0] + offset := 0 + nulcol := "[-:-:-]" + for k := range a { + if k < len(a)-1 && a[k+1]-a[k] == 1 { + end = a[k+1] + } else if k < len(a)-1 { + s = InsertAt(s, color, start+offset) + offset += len(color) + s = InsertAt(s, nulcol, end+offset+1) + offset += len(nulcol) + start = a[k+1] + end = a[k+1] + } else if k == len(a)-1 { + s = InsertAt(s, color, start+offset) + offset += len(color) + s = InsertAt(s, nulcol, end+offset+1) + offset += len(nulcol) } } - // Adding the Nulcol at the Start - s = nulcol + s return s } From a3c5af06c82828c3a1f9a03be4d5c920ca217899 Mon Sep 17 00:00:00 2001 From: aditya-K2 Date: Wed, 29 Dec 2021 23:58:21 +0530 Subject: [PATCH 07/10] Using a Unique Function Previously the bug that I mentioned here `https://github.com/aditya-K2/gomp/blob/f7c22833553e99634e032bd389eae6cf1311fd1c/utils/utils.go#L147` was caused due to the replication of matched Indexes. Hence using the utils.Unique function to only get the unique elements in the slice. --- client/updateView.go | 4 ++-- utils/utils.go | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/client/updateView.go b/client/updateView.go index e9e63de..a83b545 100644 --- a/client/updateView.go +++ b/client/updateView.go @@ -16,14 +16,14 @@ func UpdateBuffSearchView(inputTable *tview.Table, m fuzzy.Matches, f []FileNode } else { for k, v := range m { if len(f[v.Index].Children) != 0 { - inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(v.MatchedIndexes, f[v.Index].Path, "[#0000ff:-:bi]")). + inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(utils.Unique(v.MatchedIndexes), f[v.Index].Path, "[#0000ff:-:bi]")). SetAlign(tview.AlignLeft). SetStyle(tcell.StyleDefault. Foreground(tcell.ColorYellow). Background(tcell.ColorBlack). Bold(true))) } else { - inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(v.MatchedIndexes, f[v.Index].Title, "[#fbff00:-:bi]")). + inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(utils.Unique(v.MatchedIndexes), f[v.Index].Title, "[#fbff00:-:bi]")). SetAlign(tview.AlignLeft). SetStyle(tcell.StyleDefault. Foreground(tcell.ColorGreen). diff --git a/utils/utils.go b/utils/utils.go index dc18e7f..79ab01d 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -169,3 +169,15 @@ func GetMatchedString(a []int, s, color string) string { } return s } + +func Unique(intSlice []int) []int { + keys := make(map[int]bool) + list := []int{} + for _, entry := range intSlice { + if _, exists := keys[entry]; !exists { + keys[entry] = true + list = append(list, entry) + } + } + return list +} From 4a0a3e18f787a7e63969b4ac3f68ceecd780afa1 Mon Sep 17 00:00:00 2001 From: aditya-K2 Date: Thu, 30 Dec 2021 17:17:58 +0530 Subject: [PATCH 08/10] Using tcell.Colors instead of HardCoding Hex Values --- client/client.go | 2 +- client/updateView.go | 4 ++-- ui/app.go | 8 ++++---- ui/notify/notification.go | 7 ++++--- utils/utils.go | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/client/client.go b/client/client.go index 2c5d72b..bf80519 100644 --- a/client/client.go +++ b/client/client.go @@ -15,7 +15,7 @@ var ( NotificationServer interface { Send(string) } - WHITE_AND_BOLD string = "[#ffffff::b]" + WHITE_AND_BOLD string = "[white::b]" ) func SetConnection(c *mpd.Client) { diff --git a/client/updateView.go b/client/updateView.go index a83b545..a6f29d0 100644 --- a/client/updateView.go +++ b/client/updateView.go @@ -16,14 +16,14 @@ func UpdateBuffSearchView(inputTable *tview.Table, m fuzzy.Matches, f []FileNode } else { for k, v := range m { if len(f[v.Index].Children) != 0 { - inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(utils.Unique(v.MatchedIndexes), f[v.Index].Path, "[#0000ff:-:bi]")). + inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(utils.Unique(v.MatchedIndexes), f[v.Index].Path, "[blue:-:bi]")). SetAlign(tview.AlignLeft). SetStyle(tcell.StyleDefault. Foreground(tcell.ColorYellow). Background(tcell.ColorBlack). Bold(true))) } else { - inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(utils.Unique(v.MatchedIndexes), f[v.Index].Title, "[#fbff00:-:bi]")). + inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(utils.Unique(v.MatchedIndexes), f[v.Index].Title, "[yellow:-:bi]")). SetAlign(tview.AlignLeft). SetStyle(tcell.StyleDefault. Foreground(tcell.ColorGreen). diff --git a/ui/app.go b/ui/app.go index 49bf0df..633b1e0 100644 --- a/ui/app.go +++ b/ui/app.go @@ -36,10 +36,10 @@ func NewApplication() *Application { imagePreviewer.SetBackgroundColor(tcell.ColorDefault) searchBar.SetTitle("Search").SetTitleAlign(tview.AlignLeft) - searchBar.SetAutocompleteBackgroundColor(tcell.GetColor("#15191a")) - searchBar.SetAutocompleteSelectBackgroundColor(tcell.GetColor("#e5e5e5")) - searchBar.SetAutocompleteMainTextColor(tcell.GetColor("#7f7f7f")) - searchBar.SetAutocompleteSelectedTextColor(tcell.GetColor("#111111")) + searchBar.SetAutocompleteBackgroundColor(tcell.ColorBlack) + searchBar.SetAutocompleteSelectBackgroundColor(tcell.ColorWhite) + searchBar.SetAutocompleteMainTextColor(tcell.ColorDarkGray) + searchBar.SetAutocompleteSelectedTextColor(tcell.ColorBlack) Navbar.SetBorder(true) Navbar.SetSelectable(true, false) Navbar.SetCell(0, 0, tview.NewTableCell("PlayList")) diff --git a/ui/notify/notification.go b/ui/notify/notification.go index e05554f..27b62df 100644 --- a/ui/notify/notification.go +++ b/ui/notify/notification.go @@ -1,9 +1,10 @@ package notify import ( - "github.com/aditya-K2/gomp/ui" "time" + "github.com/aditya-K2/gomp/ui" + "github.com/aditya-K2/gomp/utils" "github.com/aditya-K2/tview" @@ -43,12 +44,12 @@ func (self *Notification) Draw(screen tcell.Screen) { TEXTPOSITION int = 2 ) - self.Box.SetBackgroundColor(tcell.GetColor("#15191a")) + self.Box.SetBackgroundColor(tcell.ColorBlack) self.SetRect(COL-(TEXTLENGTH+7), 1, TEXTLENGTH+4, HEIGHT) self.DrawForSubclass(screen, self.Box) tview.Print(screen, self.Text, COL-(TEXTLENGTH+5), TEXTPOSITION, TEXTLENGTH, - tview.AlignCenter, tcell.GetColor("#ffffff")) + tview.AlignCenter, tcell.ColorWhite) } /* Notification Server : Not an actual Server*/ diff --git a/utils/utils.go b/utils/utils.go index 79ab01d..51554d2 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -59,7 +59,7 @@ func InsertAt(inputString, stringTobeInserted string, index int) string { } func GetText(width, percentage float64, eta string) string { - q := "[#000000:#ffffff:b]" + q := "[black:white:b]" var a string a += strings.Repeat(" ", int(width)-len(eta)) a = InsertAt(a, eta, int(width/2)-10) From 010f2473cad8f00d6ffc626478ceb1b13b5a2c3c Mon Sep 17 00:00:00 2001 From: aditya-K2 Date: Thu, 30 Dec 2021 18:33:39 +0530 Subject: [PATCH 09/10] refactor: Minor Formatting Changes and Refactoring --- client/updateView.go | 147 ++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 92 deletions(-) diff --git a/client/updateView.go b/client/updateView.go index a6f29d0..58086f9 100644 --- a/client/updateView.go +++ b/client/updateView.go @@ -9,6 +9,15 @@ import ( "github.com/gdamore/tcell/v2" ) +func GetCell(text string, foreground tcell.Color, bold bool) *tview.TableCell { + return tview.NewTableCell(text). + SetAlign(tview.AlignLeft). + SetStyle(tcell.StyleDefault. + Foreground(foreground). + Background(tcell.ColorBlack). + Bold(bold)) +} + func UpdateBuffSearchView(inputTable *tview.Table, m fuzzy.Matches, f []FileNode) { inputTable.Clear() if m == nil || len(m) == 0 { @@ -16,19 +25,17 @@ func UpdateBuffSearchView(inputTable *tview.Table, m fuzzy.Matches, f []FileNode } else { for k, v := range m { if len(f[v.Index].Children) != 0 { - inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(utils.Unique(v.MatchedIndexes), f[v.Index].Path, "[blue:-:bi]")). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorYellow). - Background(tcell.ColorBlack). - Bold(true))) + inputTable.SetCell(k, 0, + GetCell( + utils.GetMatchedString( + utils.Unique(v.MatchedIndexes), f[v.Index].Path, "[blue:-:bi]"), + tcell.ColorYellow, true)) } else { - inputTable.SetCell(k, 0, tview.NewTableCell(utils.GetMatchedString(utils.Unique(v.MatchedIndexes), f[v.Index].Title, "[yellow:-:bi]")). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorGreen). - Background(tcell.ColorBlack). - Bold(true))) + inputTable.SetCell(k, 0, + GetCell( + utils.GetMatchedString( + utils.Unique(v.MatchedIndexes), f[v.Index].Title, "[yellow:-:bi]"), + tcell.ColorGreen, true)) } if k == 15 { break @@ -44,29 +51,19 @@ func UpdatePlaylist(inputTable *tview.Table) { for i, j := range _playlistAttr { _, _, w, _ := inputTable.GetInnerRect() if j["Title"] == "" || j["Artist"] == "" || j["Album"] == "" { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(j["file"], w/3)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorBlue). - Background(tcell.ColorBlack). - Bold(true))) + inputTable.SetCell(i, 0, + GetCell( + utils.GetFormattedString(j["file"], w/3), tcell.ColorBlue, true)) } else { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(j["Title"], w/3)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorGreen). - Background(tcell.ColorBlack))) - inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString(j["Artist"], w/3)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorPurple). - Background(tcell.ColorBlack))) - inputTable.SetCell(i, 2, tview.NewTableCell(j["Album"]). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorYellow). - Background(tcell.ColorBlack))) + inputTable.SetCell(i, 0, + GetCell( + utils.GetFormattedString(j["Title"], w/3), tcell.ColorGreen, false)) + inputTable.SetCell(i, 1, + GetCell( + utils.GetFormattedString(j["Artist"], w/3), tcell.ColorPurple, false)) + inputTable.SetCell(i, 2, + GetCell(j["Album"], tcell.ColorYellow, false)) } } } @@ -81,46 +78,33 @@ func UpdateSearchView(inputTable *tview.Table, c []interface{}) { switch content.(type) { case [3]string: { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(content.([3]string)[0], width/3)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorGreen). - Background(tcell.ColorBlack))) - inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString(content.([3]string)[1], width/3)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorPurple). - Background(tcell.ColorBlack))) - inputTable.SetCell(i, 2, tview.NewTableCell(utils.GetFormattedString(content.([3]string)[2], width/3)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorYellow). - Background(tcell.ColorBlack))) + inputTable.SetCell(i, 0, + GetCell( + utils.GetFormattedString(content.([3]string)[0], width/3), tcell.ColorGreen, false)) + inputTable.SetCell(i, 1, + GetCell( + utils.GetFormattedString(content.([3]string)[1], width/3), tcell.ColorPurple, false)) + inputTable.SetCell(i, 2, + GetCell(content.([3]string)[2], tcell.ColorYellow, false)) } case [2]string: { - inputTable.SetCell(i, 0, tview.NewTableCell(utils.GetFormattedString(content.([2]string)[0], width/3)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorYellow). - Background(tcell.ColorBlack))) - inputTable.SetCell(i, 1, tview.NewTableCell(utils.GetFormattedString(content.([2]string)[1], width/3)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorPurple). - Background(tcell.ColorBlack))) + inputTable.SetCell(i, 0, + GetCell( + utils.GetFormattedString(content.([2]string)[0], width/3), tcell.ColorYellow, false)) + inputTable.SetCell(i, 1, + GetCell( + utils.GetFormattedString(content.([2]string)[1], width/3), tcell.ColorPurple, false)) } case string: { b := content.(string) if !strings.HasPrefix(b, WHITE_AND_BOLD) { - inputTable.SetCell(i, 0, tview.NewTableCell(content.(string)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorPurple). - Background(tcell.ColorBlack))) + inputTable.SetCell(i, 0, + GetCell(content.(string), tcell.ColorPurple, false)) } else { - inputTable.SetCell(i, 0, tview.NewTableCell(content.(string)).SetSelectable(false)) + inputTable.SetCell(i, 0, + GetCell(content.(string), tcell.ColorWhite, true).SetSelectable(false)) } } } @@ -135,43 +119,22 @@ func Update(f []FileNode, inputTable *tview.Table) { if err == nil && _songAttributes[0]["Title"] != "" { _, _, w, _ := inputTable.GetInnerRect() inputTable.SetCell(i, 0, - tview.NewTableCell(utils.GetFormattedString(_songAttributes[0]["Title"], w/3)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorGreen). - Background(tcell.ColorBlack))) + GetCell( + utils.GetFormattedString(_songAttributes[0]["Title"], w/3), tcell.ColorGreen, false)) inputTable.SetCell(i, 1, - tview.NewTableCell(utils.GetFormattedString(_songAttributes[0]["Artist"], w/3)). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorPurple). - Background(tcell.ColorBlack))) - + GetCell( + utils.GetFormattedString(_songAttributes[0]["Artist"], w/3), tcell.ColorPurple, false)) inputTable.SetCell(i, 2, - tview.NewTableCell(_songAttributes[0]["Album"]). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorYellow). - Background(tcell.ColorBlack))) + GetCell(_songAttributes[0]["Album"], tcell.ColorYellow, false)) } else if _songAttributes[0]["Title"] == "" { inputTable.SetCell(i, 0, - tview.NewTableCell(j.Path). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorBlue). - Background(tcell.ColorBlack). - Bold(true))) + GetCell(j.Path, tcell.ColorBlue, true)) } } else { inputTable.SetCell(i, 0, - tview.NewTableCell(j.Path). - SetAlign(tview.AlignLeft). - SetStyle(tcell.StyleDefault. - Foreground(tcell.ColorYellow). - Background(tcell.ColorBlack). - Bold(true))) + GetCell(j.Path, tcell.ColorYellow, true)) } } } From 1c687ec3cfc9d4922b99374dd7c9a962e4e812f8 Mon Sep 17 00:00:00 2001 From: Aditya Kurdunkar <51816057+aditya-K2@users.noreply.github.com> Date: Thu, 30 Dec 2021 20:50:31 +0530 Subject: [PATCH 10/10] Update README.md --- README.md | 11 ++++++++--- extras/showcase.md | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 extras/showcase.md diff --git a/README.md b/README.md index 4e12b27..a6a0265 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,17 @@ MPD client inspired by ncmpcpp with builtin cover-art view and LastFM integration. -https://user-images.githubusercontent.com/51816057/144759799-b9eecf9e-93ad-43a7-a076-0ae47f03d03c.mp4 +![screenshot](https://user-images.githubusercontent.com/51816057/147781035-69eeeb1c-cd62-4e42-8e71-3b07538704e8.png) ## Table of Contents + * [Roadmap](#roadmap) * [Installing / Building](#installing--building) * [AUR Package](#aur-package) * [Manually](#manually) - * [Configuring gomp](#configuring-gomp) +* [Setting Up](#setting-up) + # Roadmap @@ -42,4 +44,7 @@ go build ``` --- -#### [Configuring](https://aditya-K2.github.io/gomp/) gomp +# Setting Up + +- [Configuring](https://aditya-K2.github.io/gomp/) +- [Video Showcase](https://github.com/aditya-K2/gomp/tree/master/extras/showcase.md) diff --git a/extras/showcase.md b/extras/showcase.md new file mode 100644 index 0000000..c2f1c58 --- /dev/null +++ b/extras/showcase.md @@ -0,0 +1 @@ +https://user-images.githubusercontent.com/51816057/147775581-cd2f7abb-1d9d-47e8-92ad-589a611a9386.mp4