Add option to keep row focus on sort

pull/94/head v1.6.2
Miguel Mota 3 years ago
parent 269b9ad5b7
commit 0a0530de5a

@ -53,6 +53,7 @@ type State struct {
hideMarketbar bool
hideChart bool
hideStatusbar bool
keepRowFocusOnSort bool
lastSelectedRowIndex int
marketBarHeight int
page int
@ -197,6 +198,7 @@ func NewCointop(config *Config) (*Cointop, error) {
}
ct := &Cointop{
// defaults
apiChoice: CoinGecko,
apiKeys: new(APIKeys),
forceRefresh: make(chan bool),
@ -222,6 +224,7 @@ func NewCointop(config *Config) (*Cointop, error) {
hideMarketbar: config.HideMarketbar,
hideChart: config.HideChart,
hideStatusbar: config.HideStatusbar,
keepRowFocusOnSort: false,
marketBarHeight: 1,
onlyTable: config.OnlyTable,
refreshRate: 60 * time.Second,

@ -54,7 +54,7 @@ func (ct *Cointop) SetupConfig() error {
if err := ct.parseConfig(); err != nil {
return err
}
if err := ct.loadTableColumnsFromConfig(); err != nil {
if err := ct.loadTableConfig(); err != nil {
return err
}
if err := ct.loadShortcutsFromConfig(); err != nil {
@ -280,6 +280,8 @@ func (ct *Cointop) configToToml() ([]byte, error) {
var coinsTableColumnsIfc interface{} = ct.State.coinsTableColumns
tableMapIfc := map[string]interface{}{}
tableMapIfc["columns"] = coinsTableColumnsIfc
var keepRowFocusOnSortIfc interface{} = ct.State.keepRowFocusOnSort
tableMapIfc["keep_row_focus_on_sort"] = keepRowFocusOnSortIfc
var inputs = &config{
API: apiChoiceIfc,
@ -306,6 +308,20 @@ func (ct *Cointop) configToToml() ([]byte, error) {
return b.Bytes(), nil
}
// LoadTableConfig loads table config from toml config into state struct
func (ct *Cointop) loadTableConfig() error {
err := ct.loadTableColumnsFromConfig()
if err != nil {
return err
}
keepRowFocusOnSortIfc, ok := ct.config.Table["keep_row_focus_on_sort"]
if ok {
ct.State.keepRowFocusOnSort = keepRowFocusOnSortIfc.(bool)
}
return nil
}
// LoadTableColumnsFromConfig loads preferred coins table columns from config file to struct
func (ct *Cointop) loadTableColumnsFromConfig() error {
ct.debuglog("loadTableColumnsFromConfig()")
@ -328,6 +344,7 @@ func (ct *Cointop) loadTableColumnsFromConfig() error {
ct.State.coinsTableColumns = columns
}
}
return nil
}

@ -1,6 +1,7 @@
package cointop
import (
"fmt"
"math"
)
@ -45,7 +46,7 @@ func (ct *Cointop) SetPage(page int) int {
// CursorDown moves the cursor one row down
func (ct *Cointop) CursorDown() error {
ct.debuglog("cursorDown()")
// NOTE: return if already at the bottom
// return if already at the bottom
if ct.IsLastRow() {
return nil
}
@ -65,7 +66,7 @@ func (ct *Cointop) CursorDown() error {
// CursorUp moves the cursor one row up
func (ct *Cointop) CursorUp() error {
ct.debuglog("cursorUp()")
// NOTE: return if already at the top
// return if already at the top
if ct.IsFirstRow() {
return nil
}
@ -86,7 +87,7 @@ func (ct *Cointop) CursorUp() error {
// PageDown moves the cursor one page down
func (ct *Cointop) PageDown() error {
ct.debuglog("pageDown()")
// NOTE: return if already at the bottom
// return if already at the bottom
if ct.IsLastRow() {
return nil
}
@ -94,24 +95,24 @@ func (ct *Cointop) PageDown() error {
ox, oy := ct.Views.Table.Origin() // this is prev origin position
cx := ct.Views.Table.CursorX() // relative cursor position
sy := ct.Views.Table.Height() // rows in visible view
k := oy + sy
y := oy + sy
l := ct.TableRowsLen()
// end of table
if (oy + sy + sy) > l {
k = l - sy
y = l - sy
}
// select last row if next jump is out of bounds
if k < 0 {
k = 0
if y < 0 {
y = 0
sy = l
}
if err := ct.Views.Table.SetOrigin(ox, k); err != nil {
if err := ct.Views.Table.SetOrigin(ox, y); err != nil {
return err
}
// move cursor to last line if can't scroll further
if k == oy {
if y == oy {
if err := ct.Views.Table.SetCursor(cx, sy-1); err != nil {
return err
}
@ -123,7 +124,7 @@ func (ct *Cointop) PageDown() error {
// PageUp moves the cursor one page up
func (ct *Cointop) PageUp() error {
ct.debuglog("pageUp()")
// NOTE: return if already at the top
// return if already at the top
if ct.IsFirstRow() {
return nil
}
@ -151,7 +152,7 @@ func (ct *Cointop) PageUp() error {
// NavigateFirstLine moves the cursor to the first row of the table
func (ct *Cointop) NavigateFirstLine() error {
ct.debuglog("navigateFirstLine()")
// NOTE: return if already at the top
// return if already at the top
if ct.IsFirstRow() {
return nil
}
@ -172,7 +173,7 @@ func (ct *Cointop) NavigateFirstLine() error {
// NavigateLastLine moves the cursor to the last row of the table
func (ct *Cointop) NavigateLastLine() error {
ct.debuglog("navigateLastLine()")
// NOTE: return if already at the bottom
// return if already at the bottom
if ct.IsLastRow() {
return nil
}
@ -196,7 +197,7 @@ func (ct *Cointop) NavigateLastLine() error {
// NavigatePageFirstLine moves the cursor to the visible first row of the table
func (ct *Cointop) NavigatePageFirstLine() error {
ct.debuglog("navigatePageFirstLine()")
// NOTE: return if already at the correct line
// return if already at the correct line
if ct.IsPageFirstLine() {
return nil
}
@ -212,7 +213,7 @@ func (ct *Cointop) NavigatePageFirstLine() error {
// NavigatePageMiddleLine moves the cursor to the visible middle row of the table
func (ct *Cointop) NavigatePageMiddleLine() error {
ct.debuglog("navigatePageMiddleLine()")
// NOTE: return if already at the correct line
// return if already at the correct line
if ct.IsPageMiddleLine() {
return nil
}
@ -229,7 +230,7 @@ func (ct *Cointop) NavigatePageMiddleLine() error {
// NavigatePageLastLine moves the cursor to the visible last row of the table
func (ct *Cointop) navigatePageLastLine() error {
ct.debuglog("navigatePageLastLine()")
// NOTE: return if already at the correct line
// return if already at the correct line
if ct.IsPageLastLine() {
return nil
}
@ -247,7 +248,7 @@ func (ct *Cointop) navigatePageLastLine() error {
func (ct *Cointop) NextPage() error {
ct.debuglog("nextPage()")
// NOTE: return if already at the last page
// return if already at the last page
if ct.IsLastPage() {
return nil
}
@ -262,7 +263,7 @@ func (ct *Cointop) NextPage() error {
func (ct *Cointop) PrevPage() error {
ct.debuglog("prevPage()")
// NOTE: return if already at the first page
// return if already at the first page
if ct.IsFirstPage() {
return nil
}
@ -297,7 +298,7 @@ func (ct *Cointop) PrevPageTop() error {
func (ct *Cointop) FirstPage() error {
ct.debuglog("firstPage()")
// NOTE: return if already at the first page
// return if already at the first page
if ct.IsFirstPage() {
return nil
}
@ -312,7 +313,7 @@ func (ct *Cointop) FirstPage() error {
func (ct *Cointop) LastPage() error {
ct.debuglog("lastPage()")
// NOTE: return if already at the last page
// return if already at the last page
if ct.IsLastPage() {
return nil
}
@ -402,26 +403,57 @@ func (ct *Cointop) GoToGlobalIndex(idx int) error {
return nil
}
// HighlightRow highlights the row at index
func (ct *Cointop) HighlightRow(idx int) error {
// HighlightRow highlights the row at index within page
func (ct *Cointop) HighlightRow(pageRowIndex int) error {
ct.debuglog("highlightRow()")
ct.Views.Table.SetOrigin(0, 0)
ct.Views.Table.SetCursor(0, 0)
ox := ct.Views.Table.OriginX()
cx := ct.Views.Table.CursorX()
sy := ct.Views.Table.Height()
h := ct.Views.Table.Height()
perpage := ct.TotalPerPage()
p := idx % perpage
oy := (p / sy) * sy
cy := p % sy
oy := 0
cy := 0
if h > 0 {
_ = perpage
cy = pageRowIndex % h
oy = pageRowIndex - cy
// end of page
if pageRowIndex >= perpage-h {
oy = perpage - h
cy = h - (perpage - pageRowIndex)
}
}
ct.debuglog(fmt.Sprintf("highlightRow idx:%v h:%v cy:%v oy:%v", pageRowIndex, h, cy, oy))
if oy > 0 {
ct.Views.Table.SetOrigin(ox, oy)
}
ct.Views.Table.SetCursor(cx, cy)
return nil
}
// GoToCoinRow navigates to the row of the matched coin
func (ct *Cointop) GoToCoinRow(coin *Coin) error {
ct.debuglog("goToCoinRow()")
if coin == nil {
return nil
}
idx := ct.GetGlobalCoinIndex(coin)
return ct.GoToGlobalIndex(idx)
}
// GetGlobalCoinIndex returns the index of the coin in from the coins list
func (ct *Cointop) GetGlobalCoinIndex(coin *Coin) int {
var idx int
for i, v := range ct.State.allCoins {
if v == coin {
idx = i
break
}
}
return idx
}
// CursorDownOrNextPage moves the cursor down one row or goes to the next page if cursor is on the last row
func (ct *Cointop) CursorDownOrNextPage() error {
ct.debuglog("CursorDownOrNextPage()")

@ -138,7 +138,18 @@ func (ct *Cointop) SortToggle(sortBy string, desc bool) error {
func (ct *Cointop) Sortfn(sortBy string, desc bool) func(g *gocui.Gui, v *gocui.View) error {
ct.debuglog("sortfn()")
return func(g *gocui.Gui, v *gocui.View) error {
return ct.SortToggle(sortBy, desc)
coin := ct.HighlightedRowCoin()
err := ct.SortToggle(sortBy, desc)
if err != nil {
return err
}
if ct.State.keepRowFocusOnSort {
err = ct.GoToCoinRow(coin)
if err != nil {
return err
}
}
return nil
}
}

@ -63,10 +63,14 @@ func (ct *Cointop) RefreshTable() error {
}
ct.table.HideColumHeaders = true
// highlight last row if current row is out of bounds (can happen when switching views)
currentrow := ct.HighlightedRowIndex()
if len(ct.State.coins) > currentrow {
ct.HighlightRow(currentrow)
// highlight last row if current row is out of bounds (can happen when switching views).
// make sure to not highlight row when actively navigating, otherwise
// table will appear glitchy since this is method is async.
if ct.State.lastSelectedView != "" && ct.State.lastSelectedView != ct.State.selectedView {
currentRowIdx := ct.HighlightedRowIndex()
if len(ct.State.coins) > currentRowIdx {
ct.HighlightRow(currentRowIdx)
}
}
ct.UpdateUI(func() error {
@ -161,7 +165,7 @@ func (ct *Cointop) GetTableCoinsSlice() []*Coin {
return sliced
}
// HighlightedRowIndex returns the index of the highlighted row
// HighlightedRowIndex returns the index of the highlighted row within the per-page limit
func (ct *Cointop) HighlightedRowIndex() int {
ct.debuglog("HighlightedRowIndex()")
oy := ct.Views.Table.OriginY()

@ -33,7 +33,7 @@ func NewCoinGecko() *Service {
client := gecko.NewClient(nil)
svc := &Service{
client: client,
maxResultsPerPage: 250,
maxResultsPerPage: 250, // max is 250
maxPages: 10,
cacheMap: sync.Map{},
}

@ -89,6 +89,9 @@ func (c *ChartPlot) GetChartPoints(width int) [][]rune {
func interpolateData(data []float64, width int) []float64 {
var res []float64
if len(data) == 0 {
return res
}
stepFactor := float64(len(data)-1) / float64(width-1)
res = append(res, data[0])
for i := 1; i < width-1; i++ {

Loading…
Cancel
Save