You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cointop/cointop/table.go

293 lines
6.8 KiB
Go

package cointop
import (
"fmt"
"net/url"
"strings"
"github.com/cointop-sh/cointop/pkg/ui"
log "github.com/sirupsen/logrus"
)
// TableView is structure for table view
type TableView = ui.View
// NewTableView returns a new table view
func NewTableView() *TableView {
var view *TableView = ui.NewView("table")
return view
}
const dots = "..."
// RefreshTable refreshes the table
func (ct *Cointop) RefreshTable() error {
log.Debug("RefreshTable()")
statusText := ""
switch ct.State.selectedView {
case PortfolioView:
ct.table = ct.GetPortfolioTable()
if ct.table.RowCount() == 0 {
statusText = "No holdings found. Press \"e\" on a coin to edit holdings."
}
case PriceAlertsView:
ct.table = ct.GetPriceAlertsTable()
if ct.table.RowCount() == 0 {
statusText = "No price alerts found. Press \"+\" on a coin to add a price alert."
}
default:
ct.table = ct.GetCoinsTable()
if ct.table.RowCount() == 0 {
statusText = "no coin data"
}
}
ct.table.HideColumHeaders = true
ct.UpdateUI(func() error {
ct.Views.Table.Clear()
if statusText == "" {
if ct.Views.Table.HasBacking() {
ct.table.Format().Fprint(ct.Views.Table.Backing())
}
} else {
ct.Views.Table.Update(fmt.Sprintf("\n\n%s", statusText))
}
go ct.RowChanged()
go ct.UpdateTableHeader()
go ct.UpdateMarketbar()
go ct.UpdateChart()
return nil
})
return nil
}
// UpdateTable updates the table
func (ct *Cointop) UpdateTable() error {
log.Debug("UpdateTable()")
ct.State.allCoinsSlugMap.Range(func(key, value interface{}) bool {
k := key.(string)
if v, ok := value.(*Coin); ok {
v.Favorite = ct.State.favorites[v.Name]
ct.State.allCoinsSlugMap.Store(k, v)
}
return true
})
if ct.IsFavoritesVisible() {
ct.State.coins = ct.GetFavoritesSlice()
} else if ct.IsPortfolioVisible() {
ct.State.coins = ct.GetPortfolioSlice()
} else {
// TODO: maintain state of previous sorting
if ct.State.sortBy == "holdings" {
ct.State.sortBy = "rank"
ct.State.sortDesc = false
}
ct.State.coins = ct.GetTableCoinsSlice()
}
ct.Sort(ct.State.sortBy, ct.State.sortDesc, ct.State.coins, true)
go ct.RefreshTable()
return nil
}
// GetTableCoinsSlice returns a slice of the table rows
func (ct *Cointop) GetTableCoinsSlice() []*Coin {
log.Debug("GetTableCoinsSlice()")
var sliced []*Coin
start := ct.State.page * ct.State.perPage
end := start + ct.State.perPage
allCoins := ct.AllCoins()
size := len(allCoins)
if start < 0 {
start = 0
}
if end >= size-1 {
start = int(float64(start/100) * 100)
end = size - 1
}
if start < 0 {
start = 0
}
if end >= size {
end = size - 1
}
if end < 0 {
end = 0
}
if start >= end {
return nil
}
if end > 0 {
sliced = allCoins[start:end]
// NOTE: restore rank
for _, coin := range sliced {
icoin, _ := ct.State.allCoinsSlugMap.Load(coin.Name)
if icoin != nil {
c, _ := icoin.(*Coin)
coin.Rank = c.Rank
}
}
}
return sliced
}
// HighlightedRowIndex returns the index of the highlighted row within the per-page limit
func (ct *Cointop) HighlightedRowIndex() int {
log.Debug("HighlightedRowIndex()")
oy := ct.Views.Table.OriginY()
cy := ct.Views.Table.CursorY()
idx := oy + cy
l := ct.TableRowsLen()
if idx >= l {
idx = l - 1
}
if idx < 0 {
idx = 0
}
return idx
}
// HighlightedRowCoin returns the coin at the index of the highlighted row
func (ct *Cointop) HighlightedRowCoin() *Coin {
log.Debug("HighlightedRowCoin()")
idx := ct.HighlightedRowIndex()
coins := ct.State.coins
if ct.IsPriceAlertsVisible() {
rows := ct.ActivePriceAlerts()
for i, row := range rows {
if i == idx {
return ct.CoinByName(row.CoinName)
}
}
}
if len(coins) == 0 {
return nil
}
return coins[idx]
}
// HighlightedPageRowIndex returns the index of page row of the highlighted row
func (ct *Cointop) HighlightedPageRowIndex() int {
log.Debug("HighlightedPageRowIndex()")
cy := ct.Views.Table.CursorY()
idx := cy
if idx < 0 {
idx = 0
}
return idx
}
// GetLastSelectedRowCoinIndex returns the index of the last selected row coin
func (ct *Cointop) GetLastSelectedRowCoinIndex() int {
return ct.State.lastSelectedRowIndex
}
// RowLink returns the row url link
func (ct *Cointop) RowLink() string {
log.Debug("RowLink()")
coin := ct.HighlightedRowCoin()
if coin == nil {
return ""
}
return ct.api.CoinLink(coin.Name)
}
// RowLinkShort returns a shortened version of the row url link
func (ct *Cointop) RowLinkShort() string {
log.Debug("RowLinkShort()")
link := ct.RowLink()
if link != "" {
u, err := url.Parse(link)
if err != nil {
return ""
}
host := u.Hostname()
host = strings.Replace(host, "www.", "", -1)
path := u.EscapedPath()
parts := strings.Split(path, "/")
if len(parts) > 0 {
path = parts[len(parts)-1]
}
return fmt.Sprintf("http://%s/%s/%s", host, dots, path)
}
return ""
}
// ToggleTableFullscreen toggles the table fullscreen mode
func (ct *Cointop) ToggleTableFullscreen() error {
log.Debug("ToggleTableFullscreen()")
ct.State.onlyTable = !ct.State.onlyTable
ct.State.onlyChart = false
if !ct.State.onlyTable {
// NOTE: cached values are initial config settings.
// If the only-table config was set then toggle
// all other initial hidden views.
onlyTable, _ := ct.cache.Get("onlyTable")
if onlyTable.(bool) {
ct.State.hideMarketbar = false
ct.State.hideChart = false
ct.State.hideTable = false
ct.State.hideStatusbar = false
} else {
// NOTE: cached values store initial hidden views preferences.
hideMarketbar, _ := ct.cache.Get("hideMarketbar")
ct.State.hideMarketbar = hideMarketbar.(bool)
hideChart, _ := ct.cache.Get("hideChart")
ct.State.hideChart = hideChart.(bool)
hideTable, _ := ct.cache.Get("hideTable")
ct.State.hideTable = hideTable.(bool)
hideStatusbar, _ := ct.cache.Get("hideStatusbar")
ct.State.hideStatusbar = hideStatusbar.(bool)
}
}
go func() {
ct.UpdateTable()
ct.UpdateChart()
}()
return nil
}
// SetSelectedView sets the active table view
func (ct *Cointop) SetSelectedView(viewName string) {
ct.State.lastSelectedView = ct.State.selectedView
ct.State.selectedView = viewName
}
// ToggleSelectedView toggles between current table view and last selected table view
func (ct *Cointop) ToggleSelectedView(viewName string) {
if !(ct.IsPortfolioVisible() || ct.IsFavoritesVisible()) {
ct.State.lastSelectedRowIndex = ct.HighlightedRowIndex()
}
if ct.State.lastSelectedView == "" || ct.State.selectedView != viewName {
ct.SetSelectedView(viewName)
} else {
ct.SetSelectedView(ct.State.lastSelectedView)
}
l := ct.TableRowsLen()
if ct.IsPortfolioVisible() || ct.IsFavoritesVisible() {
// highlight last row if current row is out of bounds (can happen when switching views).
currentRowIdx := ct.HighlightedRowIndex()
if currentRowIdx >= l-1 {
ct.HighlightRow(l - 1)
}
} else {
ct.HighlightRow(ct.State.lastSelectedRowIndex)
}
}