Consolidate UI packages

pull/80/head
Miguel Mota 3 years ago
parent e89c5e65f0
commit 394d35473d

@ -1,7 +1,7 @@
package main
import (
"github.com/miguelmota/cointop/cointop/cmd"
cmd "github.com/miguelmota/cointop/cmd/commands"
)
func main() {

@ -2,7 +2,7 @@ package cmd
import (
"github.com/miguelmota/cointop/cointop"
"github.com/miguelmota/cointop/cointop/common/filecache"
"github.com/miguelmota/cointop/pkg/filecache"
"github.com/spf13/cobra"
)

@ -2,7 +2,7 @@ package cmd
import (
"github.com/miguelmota/cointop/cointop"
"github.com/miguelmota/cointop/cointop/common/filecache"
"github.com/miguelmota/cointop/pkg/filecache"
"github.com/spf13/cobra"
)

@ -6,7 +6,7 @@ import (
"fmt"
"time"
cssh "github.com/miguelmota/cointop/cointop/ssh"
cssh "github.com/miguelmota/cointop/pkg/ssh"
"github.com/spf13/cobra"
)

@ -0,0 +1,18 @@
package cointop
// SetActiveView sets the active view
func (ct *Cointop) SetActiveView(v string) error {
ct.g.SetViewOnTop(v)
ct.g.SetCurrentView(v)
if v == ct.Views.SearchField.Name() {
ct.Views.SearchField.SetCursor(1, 0)
ct.Views.SearchField.Update("/")
} else if v == ct.Views.Table.Name() {
ct.g.SetViewOnTop(ct.Views.Statusbar.Name())
}
if v == ct.Views.PortfolioUpdateMenu.Name() {
ct.g.SetViewOnTop(ct.Views.Input.Name())
ct.g.SetCurrentView(ct.Views.Input.Name())
}
return nil
}

@ -6,18 +6,18 @@ import (
"sync"
"time"
"github.com/miguelmota/cointop/cointop/common/gizak/termui"
"github.com/miguelmota/cointop/cointop/common/timeutil"
"github.com/miguelmota/cointop/pkg/chartplot"
"github.com/miguelmota/cointop/pkg/timeutil"
"github.com/miguelmota/cointop/pkg/ui"
)
// ChartView is structure for chart view
type ChartView struct {
*View
}
type ChartView = ui.View
// NewChartView returns a new chart view
func NewChartView() *ChartView {
return &ChartView{NewView("chart")}
var view *ChartView = ui.NewView("chart")
return view
}
var chartLock sync.Mutex
@ -58,10 +58,6 @@ func ChartRangesMap() map[string]time.Duration {
// UpdateChart updates the chart view
func (ct *Cointop) UpdateChart() error {
ct.debuglog("UpdateChart()")
if ct.Views.Chart.Backing() == nil {
return nil
}
chartLock.Lock()
defer chartLock.Unlock()
@ -83,21 +79,15 @@ func (ct *Cointop) UpdateChart() error {
var s string
for j := range ct.State.chartPoints[i] {
p := ct.State.chartPoints[i][j]
s = fmt.Sprintf("%s%c", s, p.Ch)
s = fmt.Sprintf("%s%c", s, p)
}
body = fmt.Sprintf("%s%s\n", body, s)
}
}
ct.Update(func() error {
if ct.Views.Chart.Backing() == nil {
return nil
}
ct.Views.Chart.Backing().Clear()
fmt.Fprint(ct.Views.Chart.Backing(), ct.colorscheme.Chart(body))
return nil
ct.UpdateUI(func() error {
return ct.Views.Chart.Update(ct.colorscheme.Chart(body))
})
return nil
@ -114,12 +104,8 @@ func (ct *Cointop) ChartPoints(symbol string, name string) error {
// TODO: not do this (SoC)
go ct.UpdateMarketbar()
chart := termui.NewLineChart()
chart.Height = ct.State.chartHeight
chart.Border = false
// NOTE: empty list means don't show x-axis labels
chart.DataLabels = []string{""}
chart := chartplot.NewChartPlot()
chart.SetHeight(ct.State.chartHeight)
rangeseconds := ct.chartRangesMap[ct.State.selectedChartRange]
if ct.State.selectedChartRange == "YTD" {
@ -165,8 +151,6 @@ func (ct *Cointop) ChartPoints(symbol string, name string) error {
return nil
}
// NOTE: edit `termui.LineChart.shortenFloatVal(float64)` to not
// use exponential notation.
for i := range graphData.Price {
price := graphData.Price[i][1]
data = append(data, price)
@ -181,32 +165,8 @@ func (ct *Cointop) ChartPoints(symbol string, name string) error {
}
}
chart.Data = data
termui.Body = termui.NewGrid()
termui.Body.Width = maxX
termui.Body.AddRows(
termui.NewRow(
termui.NewCol(12, 0, chart),
),
)
var points [][]termui.Cell
// calculate layout
termui.Body.Align()
w := termui.Body.Width
h := chart.Height
row := termui.Body.Rows[0]
b := row.Buffer()
for i := 0; i < h; i = i + 1 {
var rowpoints []termui.Cell
for j := 0; j < w; j = j + 1 {
p := b.At(j, i)
rowpoints = append(rowpoints, p)
}
points = append(points, rowpoints)
}
ct.State.chartPoints = points
chart.SetData(data)
ct.State.chartPoints = chart.GetChartPoints(maxX)
return nil
}
@ -221,12 +181,8 @@ func (ct *Cointop) PortfolioChart() error {
// TODO: not do this (SoC)
go ct.UpdateMarketbar()
chart := termui.NewLineChart()
chart.Height = ct.State.chartHeight
chart.Border = false
// NOTE: empty list means don't show x-axis labels
chart.DataLabels = []string{""}
chart := chartplot.NewChartPlot()
chart.SetHeight(ct.State.chartHeight)
rangeseconds := ct.chartRangesMap[ct.State.selectedChartRange]
if ct.State.selectedChartRange == "YTD" {
@ -298,32 +254,8 @@ func (ct *Cointop) PortfolioChart() error {
}
}
chart.Data = data
termui.Body = termui.NewGrid()
termui.Body.Width = maxX
termui.Body.AddRows(
termui.NewRow(
termui.NewCol(12, 0, chart),
),
)
var points [][]termui.Cell
// calculate layout
termui.Body.Align()
w := termui.Body.Width
h := chart.Height
row := termui.Body.Rows[0]
b := row.Buffer()
for i := 0; i < h; i = i + 1 {
var rowpoints []termui.Cell
for j := 0; j < w; j = j + 1 {
p := b.At(j, i)
rowpoints = append(rowpoints, p)
}
points = append(points, rowpoints)
}
ct.State.chartPoints = points
chart.SetData(data)
ct.State.chartPoints = chart.GetChartPoints(maxX)
return nil
}
@ -434,15 +366,9 @@ func (ct *Cointop) ToggleCoinChart() error {
// ShowChartLoader shows chart loading indicator
func (ct *Cointop) ShowChartLoader() error {
ct.debuglog("ShowChartLoader()")
ct.Update(func() error {
if ct.Views.Chart.Backing() == nil {
return nil
}
ct.UpdateUI(func() error {
content := "\n\nLoading..."
ct.Views.Chart.Backing().Clear()
fmt.Fprint(ct.Views.Chart.Backing(), ct.colorscheme.Chart(content))
return nil
return ct.Views.Chart.Update(ct.colorscheme.Chart(content))
})
return nil

@ -9,12 +9,12 @@ import (
"sync"
"time"
"github.com/miguelmota/cointop/cointop/common/api"
"github.com/miguelmota/cointop/cointop/common/api/types"
"github.com/miguelmota/cointop/cointop/common/filecache"
"github.com/miguelmota/cointop/cointop/common/gizak/termui"
"github.com/miguelmota/cointop/cointop/common/pathutil"
"github.com/miguelmota/cointop/cointop/common/table"
"github.com/miguelmota/cointop/pkg/api"
"github.com/miguelmota/cointop/pkg/api/types"
"github.com/miguelmota/cointop/pkg/filecache"
"github.com/miguelmota/cointop/pkg/pathutil"
"github.com/miguelmota/cointop/pkg/table"
"github.com/miguelmota/cointop/pkg/ui"
"github.com/miguelmota/gocui"
"github.com/patrickmn/go-cache"
)
@ -44,7 +44,7 @@ type State struct {
allCoinsSlugMap sync.Map
cacheDir string
coins []*Coin
chartPoints [][]termui.Cell
chartPoints [][]rune
currencyConversion string
convertMenuVisible bool
defaultView string
@ -79,6 +79,7 @@ type State struct {
// Cointop cointop
type Cointop struct {
g *gocui.Gui
ui *ui.UI
ActionsMap map[string]bool
apiKeys *APIKeys
cache *cache.Cache
@ -406,26 +407,27 @@ func NewCointop(config *Config) (*Cointop, error) {
// Run runs cointop
func (ct *Cointop) Run() error {
ct.debuglog("run()")
g, err := gocui.NewGui(gocui.Output256)
ui, err := ui.NewUI()
if err != nil {
return fmt.Errorf("new gocui: %v", err)
return err
}
g.FgColor = ct.colorscheme.BaseFg()
g.BgColor = ct.colorscheme.BaseBg()
ct.g = g
defer g.Close()
ui.SetFgColor(ct.colorscheme.BaseFg())
ui.SetBgColor(ct.colorscheme.BaseBg())
ct.ui = ui
ct.g = ui.GetGocui()
defer ui.Close()
g.InputEsc = true
g.Mouse = true
g.Highlight = true
g.SetManagerFunc(ct.layout)
if err := ct.Keybindings(g); err != nil {
ui.SetInputEsc(true)
ui.SetMouse(true)
ui.SetHighlight(true)
ui.SetManagerFunc(ct.layout)
if err := ct.Keybindings(ct.g); err != nil {
return fmt.Errorf("keybindings: %v", err)
}
ct.State.running = true
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
if err := ui.MainLoop(); err != nil && err != gocui.ErrQuit {
return fmt.Errorf("main loop: %v", err)
}

@ -229,18 +229,6 @@ func (c *Colorscheme) TableRowFavoriteSprintf() ISprintf {
return c.toSprintf("table_row_favorite")
}
// SetViewColor ...
func (c *Colorscheme) SetViewColor(view *gocui.View, name string) {
view.FgColor = c.gocuiFgColor(name)
view.BgColor = c.gocuiBgColor(name)
}
// SetViewActiveColor ...
func (c *Colorscheme) SetViewActiveColor(view *gocui.View, name string) {
view.SelFgColor = c.gocuiFgColor(name)
view.SelBgColor = c.gocuiBgColor(name)
}
func (c *Colorscheme) toSprintf(name string) ISprintf {
if cached, ok := c.cache[name]; ok {
return cached

@ -10,7 +10,7 @@ import (
"time"
"github.com/BurntSushi/toml"
"github.com/miguelmota/cointop/cointop/common/pathutil"
"github.com/miguelmota/cointop/pkg/pathutil"
)
var fileperm = os.FileMode(0644)

@ -6,8 +6,9 @@ import (
"sort"
"strings"
color "github.com/miguelmota/cointop/cointop/common/color"
"github.com/miguelmota/cointop/cointop/common/pad"
color "github.com/miguelmota/cointop/pkg/color"
"github.com/miguelmota/cointop/pkg/pad"
"github.com/miguelmota/cointop/pkg/ui"
)
// FiatCurrencyNames is a mpa of currency symbols to names.
@ -105,13 +106,12 @@ var CurrencySymbolMap = map[string]string{
var alphanumericcharacters = []rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}
// ConvertMenuView is structure for convert menu view
type ConvertMenuView struct {
*View
}
type ConvertMenuView = ui.View
// NewConvertMenuView returns a new convert menu view
func NewConvertMenuView() *ConvertMenuView {
return &ConvertMenuView{NewView("convertmenu")}
var view *ConvertMenuView = ui.NewView("convertmenu")
return view
}
// IsSupportedCurrencyConversion returns true if it's a supported currency conversion
@ -158,7 +158,7 @@ func (ct *Cointop) SortedSupportedCurrencyConversions() []string {
}
// UpdateConvertMenu updates the convert menu
func (ct *Cointop) UpdateConvertMenu() {
func (ct *Cointop) UpdateConvertMenu() error {
ct.debuglog("updateConvertMenu()")
header := ct.colorscheme.MenuHeader(fmt.Sprintf(" Currency Conversion %s\n\n", pad.Left("[q] close menu ", ct.maxTableWidth-20, " ")))
helpline := " Press the corresponding key to select currency for conversion\n\n"
@ -204,16 +204,12 @@ func (ct *Cointop) UpdateConvertMenu() {
}
content := fmt.Sprintf("%s%s%s", header, helpline, body)
ct.Update(func() error {
if ct.Views.ConvertMenu.Backing() == nil {
return nil
}
ct.Views.ConvertMenu.Backing().Clear()
ct.Views.ConvertMenu.Backing().Frame = true
fmt.Fprintln(ct.Views.ConvertMenu.Backing(), content)
return nil
ct.UpdateUI(func() error {
ct.Views.ConvertMenu.SetFrame(true)
return ct.Views.ConvertMenu.Update(content)
})
return nil
}
// SetCurrencyConverstion sets the currency conversion
@ -274,16 +270,11 @@ func (ct *Cointop) ShowConvertMenu() error {
func (ct *Cointop) HideConvertMenu() error {
ct.debuglog("hideConvertMenu()")
ct.State.convertMenuVisible = false
ct.SetViewOnBottom(ct.Views.ConvertMenu.Name())
ct.ui.SetViewOnBottom(ct.Views.ConvertMenu)
ct.SetActiveView(ct.Views.Table.Name())
ct.Update(func() error {
if ct.Views.ConvertMenu.Backing() == nil {
return nil
}
ct.Views.ConvertMenu.Backing().Clear()
ct.Views.ConvertMenu.Backing().Frame = false
fmt.Fprintln(ct.Views.ConvertMenu.Backing(), "")
ct.UpdateUI(func() error {
ct.Views.ConvertMenu.SetFrame(false)
return ct.Views.ConvertMenu.Update("")
return nil
})
return nil

@ -3,7 +3,7 @@ package cointop
import (
"fmt"
"github.com/miguelmota/cointop/cointop/common/api"
"github.com/miguelmota/cointop/pkg/api"
)
// DominanceConfig is the config options for the dominance command

@ -4,17 +4,17 @@ import (
"fmt"
"sort"
"github.com/miguelmota/cointop/cointop/common/pad"
"github.com/miguelmota/cointop/pkg/pad"
"github.com/miguelmota/cointop/pkg/ui"
)
// HelpView is structure for help view
type HelpView struct {
*View
}
type HelpView = ui.View
// NewHelpView returns a new help view
func NewHelpView() *HelpView {
return &HelpView{NewView("help")}
var view *HelpView = ui.NewView("help")
return view
}
// UpdateHelp updates the help views
@ -60,15 +60,9 @@ func (ct *Cointop) UpdateHelp() {
infoLine := "See git.io/cointop for more info.\n Press ESC to return."
content := fmt.Sprintf("%s %s\n %s\n\n %s\n\n%s\n %s", header, versionLine, licenseLine, instructionsLine, body, infoLine)
ct.Update(func() error {
if ct.Views.Help.Backing() == nil {
return nil
}
ct.Views.Help.Backing().Clear()
ct.Views.Help.Backing().Frame = true
fmt.Fprintln(ct.Views.Help.Backing(), content)
return nil
ct.UpdateUI(func() error {
ct.Views.Help.SetFrame(true)
return ct.Views.Help.Update(content)
})
}
@ -85,17 +79,11 @@ func (ct *Cointop) ShowHelp() error {
func (ct *Cointop) HideHelp() error {
ct.debuglog("hideHelp()")
ct.State.helpVisible = false
ct.SetViewOnBottom(ct.Views.Help.Name())
ct.ui.SetViewOnBottom(ct.Views.Help)
ct.SetActiveView(ct.Views.Table.Name())
ct.Update(func() error {
if ct.Views.Help.Backing() == nil {
return nil
}
ct.Views.Help.Backing().Clear()
ct.Views.Help.Backing().Frame = false
fmt.Fprintln(ct.Views.Help.Backing(), "")
return nil
ct.UpdateUI(func() error {
ct.Views.Help.SetFrame(false)
return ct.Views.Help.Update("")
})
return nil
}

@ -3,8 +3,6 @@ package cointop
import (
"fmt"
"strings"
"github.com/miguelmota/gocui"
)
// TODO: break up into small functions
@ -12,7 +10,7 @@ import (
var lastWidth int
// layout sets initial layout
func (ct *Cointop) layout(g *gocui.Gui) error {
func (ct *Cointop) layout() error {
ct.debuglog("layout()")
maxY := ct.height()
maxX := ct.ClampedWidth()
@ -43,13 +41,10 @@ func (ct *Cointop) layout(g *gocui.Gui) error {
}
if !ct.State.hideMarketbar {
if v, err := g.SetView(ct.Views.Marketbar.Name(), 0, topOffset, maxX, 2); err != nil {
if err != gocui.ErrUnknownView {
return err
}
ct.Views.Marketbar.SetBacking(v)
ct.Views.Marketbar.Backing().Frame = false
ct.colorscheme.SetViewColor(ct.Views.Marketbar.Backing(), "marketbar")
if err := ct.ui.SetView(ct.Views.Marketbar, 0, topOffset, maxX, 2); err != nil {
ct.Views.Marketbar.SetFrame(false)
ct.Views.Marketbar.SetFgColor(ct.colorscheme.gocuiFgColor(ct.Views.Marketbar.Name()))
ct.Views.Marketbar.SetBgColor(ct.colorscheme.gocuiBgColor(ct.Views.Marketbar.Name()))
go func() {
ct.UpdateMarketbar()
_, found := ct.cache.Get(ct.Views.Marketbar.Name())
@ -61,7 +56,7 @@ func (ct *Cointop) layout(g *gocui.Gui) error {
}
} else {
if ct.Views.Marketbar.Backing() != nil {
if err := g.DeleteView(ct.Views.Marketbar.Name()); err != nil {
if err := ct.g.DeleteView(ct.Views.Marketbar.Name()); err != nil {
return err
}
ct.Views.Marketbar.SetBacking(nil)
@ -71,14 +66,11 @@ func (ct *Cointop) layout(g *gocui.Gui) error {
topOffset = topOffset + marketbarHeight
if !ct.State.hideChart {
if v, err := g.SetView(ct.Views.Chart.Name(), 0, topOffset, maxX, topOffset+chartHeight+marketbarHeight); err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.Clear()
ct.Views.Chart.SetBacking(v)
ct.Views.Chart.Backing().Frame = false
ct.colorscheme.SetViewColor(ct.Views.Chart.Backing(), "chart")
if err := ct.ui.SetView(ct.Views.Chart, 0, topOffset, maxX, topOffset+chartHeight+marketbarHeight); err != nil {
ct.Views.Chart.Clear()
ct.Views.Chart.SetFrame(false)
ct.Views.Chart.SetFgColor(ct.colorscheme.gocuiFgColor(ct.Views.Chart.Name()))
ct.Views.Chart.SetBgColor(ct.colorscheme.gocuiBgColor(ct.Views.Chart.Name()))
go func() {
ct.UpdateChart()
cachekey := strings.ToLower(fmt.Sprintf("%s_%s", "globaldata", strings.Replace(ct.State.selectedChartRange, " ", "", -1)))
@ -91,7 +83,7 @@ func (ct *Cointop) layout(g *gocui.Gui) error {
}
} else {
if ct.Views.Chart.Backing() != nil {
if err := g.DeleteView(ct.Views.Chart.Name()); err != nil {
if err := ct.g.DeleteView(ct.Views.Chart.Name()); err != nil {
return err
}
ct.Views.Chart.SetBacking(nil)
@ -99,25 +91,19 @@ func (ct *Cointop) layout(g *gocui.Gui) error {
}
topOffset = topOffset + chartHeight
if v, err := g.SetView(ct.Views.TableHeader.Name(), 0, topOffset, ct.maxTableWidth, topOffset+2); err != nil {
if err != gocui.ErrUnknownView {
return err
}
ct.Views.TableHeader.SetBacking(v)
ct.Views.TableHeader.Backing().Frame = false
ct.colorscheme.SetViewColor(ct.Views.TableHeader.Backing(), "table_header")
if err := ct.ui.SetView(ct.Views.TableHeader, 0, topOffset, ct.maxTableWidth, topOffset+2); err != nil {
ct.Views.TableHeader.SetFrame(false)
ct.Views.TableHeader.SetFgColor(ct.colorscheme.gocuiFgColor(ct.Views.TableHeader.Name()))
ct.Views.TableHeader.SetBgColor(ct.colorscheme.gocuiBgColor(ct.Views.TableHeader.Name()))
go ct.UpdateTableHeader()
}
topOffset = topOffset + headerHeight
if v, err := g.SetView(ct.Views.Table.Name(), 0, topOffset, ct.maxTableWidth, maxY-statusbarHeight); err != nil {
if err != gocui.ErrUnknownView {
return err
}
ct.Views.Table.SetBacking(v)
ct.Views.Table.Backing().Frame = false
ct.Views.Table.Backing().Highlight = true
ct.colorscheme.SetViewActiveColor(ct.Views.Table.Backing(), "table_row_active")
if err := ct.ui.SetView(ct.Views.Table, 0, topOffset, ct.maxTableWidth, maxY-statusbarHeight); err != nil {
ct.Views.Table.SetFrame(false)
ct.Views.Table.SetHighlight(true)
ct.Views.Table.SetSelFgColor(ct.colorscheme.gocuiFgColor("table_row_active"))
ct.Views.Table.SetSelBgColor(ct.colorscheme.gocuiBgColor("table_row_active"))
_, found := ct.cache.Get("allCoinsSlugMap")
if found {
ct.cache.Delete("allCoinsSlugMap")
@ -129,80 +115,61 @@ func (ct *Cointop) layout(g *gocui.Gui) error {
}
if !ct.State.hideStatusbar {
if v, err := g.SetView(ct.Views.Statusbar.Name(), 0, maxY-statusbarHeight-1, ct.maxTableWidth, maxY); err != nil {
if err != gocui.ErrUnknownView {
return err
}
ct.Views.Statusbar.SetBacking(v)
ct.Views.Statusbar.Backing().Frame = false
ct.colorscheme.SetViewColor(ct.Views.Statusbar.Backing(), "statusbar")
if err := ct.ui.SetView(ct.Views.Statusbar, 0, maxY-statusbarHeight-1, ct.maxTableWidth, maxY); err != nil {
ct.Views.Statusbar.SetFrame(false)
ct.Views.Statusbar.SetFgColor(ct.colorscheme.gocuiFgColor(ct.Views.Statusbar.Name()))
ct.Views.Statusbar.SetBgColor(ct.colorscheme.gocuiBgColor(ct.Views.Statusbar.Name()))
go ct.UpdateStatusbar("")
}
} else {
if ct.Views.Statusbar.Backing() != nil {
if err := g.DeleteView(ct.Views.Statusbar.Name()); err != nil {
if err := ct.g.DeleteView(ct.Views.Statusbar.Name()); err != nil {
return err
}
ct.Views.Statusbar.SetBacking(nil)
}
}
if v, err := g.SetView(ct.Views.SearchField.Name(), 0, maxY-2, ct.maxTableWidth, maxY); err != nil {
if err != gocui.ErrUnknownView {
return err
}
ct.Views.SearchField.SetBacking(v)
ct.Views.SearchField.Backing().Editable = true
ct.Views.SearchField.Backing().Wrap = true
ct.Views.SearchField.Backing().Frame = false
ct.colorscheme.SetViewColor(ct.Views.SearchField.Backing(), "searchbar")
if err := ct.ui.SetView(ct.Views.SearchField, 0, maxY-2, ct.maxTableWidth, maxY); err != nil {
ct.Views.SearchField.SetEditable(true)
ct.Views.SearchField.SetWrap(true)
ct.Views.SearchField.SetFrame(false)
ct.Views.SearchField.SetFgColor(ct.colorscheme.gocuiFgColor("searchbar"))
ct.Views.SearchField.SetBgColor(ct.colorscheme.gocuiBgColor("searchbar"))
}
if v, err := g.SetView(ct.Views.Help.Name(), 1, 1, ct.maxTableWidth-1, maxY-1); err != nil {
if err != gocui.ErrUnknownView {
return err
}
ct.Views.Help.SetBacking(v)
ct.Views.Help.Backing().Frame = false
ct.colorscheme.SetViewColor(ct.Views.Help.Backing(), "menu")
if err := ct.ui.SetView(ct.Views.Help, 1, 1, ct.maxTableWidth-1, maxY-1); err != nil {
ct.Views.Help.SetFrame(false)
ct.Views.Help.SetFgColor(ct.colorscheme.gocuiFgColor("menu"))
ct.Views.Help.SetBgColor(ct.colorscheme.gocuiBgColor("menu"))
}
if v, err := g.SetView(ct.Views.PortfolioUpdateMenu.Name(), 1, 1, ct.maxTableWidth-1, maxY-1); err != nil {
if err != gocui.ErrUnknownView {
return err
}
ct.Views.PortfolioUpdateMenu.SetBacking(v)
ct.Views.PortfolioUpdateMenu.Backing().Frame = false
ct.colorscheme.SetViewColor(ct.Views.PortfolioUpdateMenu.Backing(), "menu")
if err := ct.ui.SetView(ct.Views.PortfolioUpdateMenu, 1, 1, ct.maxTableWidth-1, maxY-1); err != nil {
ct.Views.PortfolioUpdateMenu.SetFrame(false)
ct.Views.PortfolioUpdateMenu.SetFgColor(ct.colorscheme.gocuiFgColor("menu"))
ct.Views.PortfolioUpdateMenu.SetBgColor(ct.colorscheme.gocuiBgColor("menu"))
}
if v, err := g.SetView(ct.Views.Input.Name(), 3, 6, 30, 8); err != nil {
if err != gocui.ErrUnknownView {
return err
}
ct.Views.Input.SetBacking(v)
ct.Views.Input.Backing().Frame = true
ct.Views.Input.Backing().Editable = true
ct.Views.Input.Backing().Wrap = true
ct.colorscheme.SetViewColor(ct.Views.Input.Backing(), "menu")
if err := ct.ui.SetView(ct.Views.Input, 3, 6, 30, 8); err != nil {
ct.Views.Input.SetFrame(true)
ct.Views.Input.SetEditable(true)
ct.Views.Input.SetWrap(true)
ct.Views.Input.SetFgColor(ct.colorscheme.gocuiFgColor("menu"))
ct.Views.Input.SetBgColor(ct.colorscheme.gocuiBgColor("menu"))
}
if v, err := g.SetView(ct.Views.ConvertMenu.Name(), 1, 1, ct.maxTableWidth-1, maxY-1); err != nil {
if err != gocui.ErrUnknownView {
return err
}
ct.Views.ConvertMenu.SetBacking(v)
ct.Views.ConvertMenu.Backing().Frame = false
ct.colorscheme.SetViewColor(ct.Views.ConvertMenu.Backing(), "menu")
if err := ct.ui.SetView(ct.Views.ConvertMenu, 1, 1, ct.maxTableWidth-1, maxY-1); err != nil {
ct.Views.ConvertMenu.SetFrame(false)
ct.Views.ConvertMenu.SetFgColor(ct.colorscheme.gocuiFgColor("menu"))
ct.Views.ConvertMenu.SetBgColor(ct.colorscheme.gocuiBgColor("menu"))
// run only once on init.
// this bit of code should be at the bottom
ct.g = g
g.SetViewOnBottom(ct.Views.SearchField.Name()) // hide
g.SetViewOnBottom(ct.Views.Help.Name()) // hide
g.SetViewOnBottom(ct.Views.ConvertMenu.Name()) // hide
g.SetViewOnBottom(ct.Views.PortfolioUpdateMenu.Name()) // hide
g.SetViewOnBottom(ct.Views.Input.Name()) // hide
ct.ui.SetViewOnBottom(ct.Views.SearchField) // hide
ct.ui.SetViewOnBottom(ct.Views.Help) // hide
ct.ui.SetViewOnBottom(ct.Views.ConvertMenu) // hide
ct.ui.SetViewOnBottom(ct.Views.PortfolioUpdateMenu) // hide
ct.ui.SetViewOnBottom(ct.Views.Input) // hide
ct.SetActiveView(ct.Views.Table.Name())
ct.intervalFetchData()
}

@ -4,7 +4,7 @@ import (
"sync"
"time"
types "github.com/miguelmota/cointop/cointop/common/api/types"
types "github.com/miguelmota/cointop/pkg/api/types"
)
var coinslock sync.Mutex

@ -5,29 +5,25 @@ import (
"math"
"time"
types "github.com/miguelmota/cointop/cointop/common/api/types"
"github.com/miguelmota/cointop/cointop/common/color"
"github.com/miguelmota/cointop/cointop/common/humanize"
"github.com/miguelmota/cointop/cointop/common/pad"
types "github.com/miguelmota/cointop/pkg/api/types"
"github.com/miguelmota/cointop/pkg/color"
"github.com/miguelmota/cointop/pkg/humanize"
"github.com/miguelmota/cointop/pkg/pad"
"github.com/miguelmota/cointop/pkg/ui"
)
// MarketbarView is structure for marketbar view
type MarketbarView struct {
*View
}
type MarketbarView = ui.View
// NewMarketbarView returns a new marketbar view
func NewMarketbarView() *MarketbarView {
return &MarketbarView{NewView("marketbar")}
var view *MarketbarView = ui.NewView("marketbar")
return view
}
// UpdateMarketbar updates the market bar view
func (ct *Cointop) UpdateMarketbar() error {
ct.debuglog("updateMarketbar()")
if ct.Views.Marketbar.Backing() == nil {
return nil
}
maxX := ct.width()
logo := "cointop"
if ct.colorschemeName == "cointop" {
@ -147,14 +143,8 @@ func (ct *Cointop) UpdateMarketbar() error {
content = pad.Right(content, maxX, " ")
content = ct.colorscheme.Marketbar(content)
ct.Update(func() error {
if ct.Views.Marketbar.Backing() == nil {
return nil
}
ct.Views.Marketbar.Backing().Clear()
fmt.Fprintln(ct.Views.Marketbar.Backing(), content)
return nil
ct.UpdateUI(func() error {
return ct.Views.Marketbar.Update(content)
})
return nil

@ -41,21 +41,16 @@ func (ct *Cointop) SetPage(page int) int {
// CursorDown moves the cursor one row down
func (ct *Cointop) CursorDown() error {
ct.debuglog("cursorDown()")
if ct.Views.Table.Backing() == nil {
return nil
}
// NOTE: return if already at the bottom
if ct.IsLastRow() {
return nil
}
cx, cy := ct.Views.Table.Backing().Cursor()
if err := ct.Views.Table.Backing().SetCursor(cx, cy+1); err != nil {
ox, oy := ct.Views.Table.Backing().Origin()
cx, cy := ct.Views.Table.Cursor()
if err := ct.Views.Table.SetCursor(cx, cy+1); err != nil {
ox, oy := ct.Views.Table.Origin()
// set origin scrolls
if err := ct.Views.Table.Backing().SetOrigin(ox, oy+1); err != nil {
if err := ct.Views.Table.SetOrigin(ox, oy+1); err != nil {
return err
}
}
@ -66,21 +61,17 @@ func (ct *Cointop) CursorDown() error {
// CursorUp moves the cursor one row up
func (ct *Cointop) CursorUp() error {
ct.debuglog("cursorUp()")
if ct.Views.Table.Backing() == nil {
return nil
}
// NOTE: return if already at the top
if ct.IsFirstRow() {
return nil
}
ox, oy := ct.Views.Table.Backing().Origin()
cx, cy := ct.Views.Table.Backing().Cursor()
ox, oy := ct.Views.Table.Origin()
cx, cy := ct.Views.Table.Cursor()
if err := ct.Views.Table.Backing().SetCursor(cx, cy-1); err != nil && oy > 0 {
if err := ct.Views.Table.SetCursor(cx, cy-1); err != nil && oy > 0 {
// set origin scrolls
if err := ct.Views.Table.Backing().SetOrigin(ox, oy-1); err != nil {
if err := ct.Views.Table.SetOrigin(ox, oy-1); err != nil {
return err
}
}
@ -91,18 +82,14 @@ func (ct *Cointop) CursorUp() error {
// PageDown moves the cursor one page down
func (ct *Cointop) PageDown() error {
ct.debuglog("pageDown()")
if ct.Views.Table.Backing() == nil {
return nil
}
// NOTE: return if already at the bottom
if ct.IsLastRow() {
return nil
}
ox, oy := ct.Views.Table.Backing().Origin() // this is prev origin position
cx, _ := ct.Views.Table.Backing().Cursor() // relative cursor position
_, sy := ct.Views.Table.Backing().Size() // rows in visible view
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
l := len(ct.State.coins)
// end of table
@ -115,12 +102,13 @@ func (ct *Cointop) PageDown() error {
sy = l
}
if err := ct.Views.Table.Backing().SetOrigin(ox, k); err != nil {
if err := ct.Views.Table.SetOrigin(ox, k); err != nil {
return err
}
// move cursor to last line if can't scroll further
if k == oy {
if err := ct.Views.Table.Backing().SetCursor(cx, sy-1); err != nil {
if err := ct.Views.Table.SetCursor(cx, sy-1); err != nil {
return err
}
}
@ -131,28 +119,24 @@ func (ct *Cointop) PageDown() error {
// PageUp moves the cursor one page up
func (ct *Cointop) PageUp() error {
ct.debuglog("pageUp()")
if ct.Views.Table.Backing() == nil {
return nil
}
// NOTE: return if already at the top
if ct.IsFirstRow() {
return nil
}
ox, oy := ct.Views.Table.Backing().Origin()
cx, _ := ct.Views.Table.Backing().Cursor() // relative cursor position
_, sy := ct.Views.Table.Backing().Size() // rows in visible view
ox, oy := ct.Views.Table.Origin()
cx := ct.Views.Table.CursorX() // relative cursor position
sy := ct.Views.Table.Height() // rows in visible view
k := oy - sy
if k < 0 {
k = 0
}
if err := ct.Views.Table.Backing().SetOrigin(ox, k); err != nil {
if err := ct.Views.Table.SetOrigin(ox, k); err != nil {
return err
}
// move cursor to first line if can't scroll further
if k == oy {
if err := ct.Views.Table.Backing().SetCursor(cx, 0); err != nil {
if err := ct.Views.Table.SetCursor(cx, 0); err != nil {
return err
}
}
@ -163,21 +147,17 @@ func (ct *Cointop) PageUp() error {
// NavigateFirstLine moves the cursor to the first row of the table
func (ct *Cointop) NavigateFirstLine() error {
ct.debuglog("navigateFirstLine()")
if ct.Views.Table.Backing() == nil {
return nil
}
// NOTE: return if already at the top
if ct.IsFirstRow() {
return nil
}
ox, _ := ct.Views.Table.Backing().Origin()
cx, _ := ct.Views.Table.Backing().Cursor()
if err := ct.Views.Table.Backing().SetOrigin(ox, 0); err != nil {
ox := ct.Views.Table.OriginX()
cx := ct.Views.Table.CursorX()
if err := ct.Views.Table.SetOrigin(ox, 0); err != nil {
return err
}
if err := ct.Views.Table.Backing().SetCursor(cx, 0); err != nil {
if err := ct.Views.Table.SetCursor(cx, 0); err != nil {
return err
}
@ -188,24 +168,20 @@ func (ct *Cointop) NavigateFirstLine() error {
// NavigateLastLine moves the cursor to the last row of the table
func (ct *Cointop) NavigateLastLine() error {
ct.debuglog("navigateLastLine()")
if ct.Views.Table.Backing() == nil {
return nil
}
// NOTE: return if already at the bottom
if ct.IsLastRow() {
return nil
}
ox, _ := ct.Views.Table.Backing().Origin()
cx, _ := ct.Views.Table.Backing().Cursor()
_, sy := ct.Views.Table.Backing().Size()
ox := ct.Views.Table.OriginX()
cx := ct.Views.Table.CursorX()
sy := ct.Views.Table.Height()
l := len(ct.State.coins)
k := l - sy
if err := ct.Views.Table.Backing().SetOrigin(ox, k); err != nil {
if err := ct.Views.Table.SetOrigin(ox, k); err != nil {
return err
}
if err := ct.Views.Table.Backing().SetCursor(cx, sy-1); err != nil {
if err := ct.Views.Table.SetCursor(cx, sy-1); err != nil {
return err
}
@ -216,17 +192,13 @@ 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()")
if ct.Views.Table.Backing() == nil {
return nil
}
// NOTE: return if already at the correct line
if ct.IsPageFirstLine() {
return nil
}
cx, _ := ct.Views.Table.Backing().Cursor()
if err := ct.Views.Table.Backing().SetCursor(cx, 0); err != nil {
cx := ct.Views.Table.CursorX()
if err := ct.Views.Table.SetCursor(cx, 0); err != nil {
return err
}
ct.RowChanged()
@ -236,18 +208,14 @@ 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()")
if ct.Views.Table.Backing() == nil {
return nil
}
// NOTE: return if already at the correct line
if ct.IsPageMiddleLine() {
return nil
}
cx, _ := ct.Views.Table.Backing().Cursor()
_, sy := ct.Views.Table.Backing().Size()
if err := ct.Views.Table.Backing().SetCursor(cx, (sy/2)-1); err != nil {
cx := ct.Views.Table.CursorX()
sy := ct.Views.Table.Height()
if err := ct.Views.Table.SetCursor(cx, (sy/2)-1); err != nil {
return err
}
ct.RowChanged()
@ -257,18 +225,14 @@ 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()")
if ct.Views.Table.Backing() == nil {
return nil
}
// NOTE: return if already at the correct line
if ct.IsPageLastLine() {
return nil
}
cx, _ := ct.Views.Table.Backing().Cursor()
_, sy := ct.Views.Table.Backing().Size()
if err := ct.Views.Table.Backing().SetCursor(cx, sy-1); err != nil {
cx, _ := ct.Views.Table.Cursor()
sy := ct.Views.Table.Height()
if err := ct.Views.Table.SetCursor(cx, sy-1); err != nil {
return err
}
ct.RowChanged()
@ -358,28 +322,20 @@ func (ct *Cointop) LastPage() error {
// IsFirstRow returns true if cursor is on first row
func (ct *Cointop) IsFirstRow() bool {
ct.debuglog("isFirstRow()")
if ct.Views.Table.Backing() == nil {
return false
}
_, y := ct.Views.Table.Backing().Origin()
_, cy := ct.Views.Table.Backing().Cursor()
oy := ct.Views.Table.OriginY()
cy := ct.Views.Table.CursorY()
return (cy + y) == 0
return (cy + oy) == 0
}
// IsLastRow returns true if cursor is on last row
func (ct *Cointop) IsLastRow() bool {
ct.debuglog("isLastRow()")
if ct.Views.Table.Backing() == nil {
return false
}
_, y := ct.Views.Table.Backing().Origin()
_, cy := ct.Views.Table.Backing().Cursor()
oy := ct.Views.Table.OriginY()
cy := ct.Views.Table.CursorY()
numRows := len(ct.State.coins) - 1
return (cy + y + 1) > numRows
return (cy + oy + 1) > numRows
}
// IsFirstPage returns true if cursor is on the first page
@ -397,23 +353,16 @@ func (ct *Cointop) IsLastPage() bool {
// IsPageFirstLine returns true if the cursor is on the visible first row
func (ct *Cointop) IsPageFirstLine() bool {
ct.debuglog("isPageFirstLine()")
if ct.Views.Table.Backing() == nil {
return false
}
_, cy := ct.Views.Table.Backing().Cursor()
cy := ct.Views.Table.CursorY()
return cy == 0
}
// IsPageMiddleLine returns true if the cursor is on the visible middle row
func (ct *Cointop) IsPageMiddleLine() bool {
ct.debuglog("isPageMiddleLine()")
if ct.Views.Table.Backing() == nil {
return false
}
_, cy := ct.Views.Table.Backing().Cursor()
_, sy := ct.Views.Table.Backing().Size()
cy := ct.Views.Table.CursorY()
sy := ct.Views.Table.Height()
return (sy/2)-1 == cy
}
@ -421,19 +370,16 @@ func (ct *Cointop) IsPageMiddleLine() bool {
func (ct *Cointop) IsPageLastLine() bool {
ct.debuglog("isPageLastLine()")
_, cy := ct.Views.Table.Backing().Cursor()
_, sy := ct.Views.Table.Backing().Size()
cy := ct.Views.Table.CursorY()
sy := ct.Views.Table.Height()
return cy+1 == sy
}
// GoToPageRowIndex navigates to the selected row index of the page
func (ct *Cointop) GoToPageRowIndex(idx int) error {
ct.debuglog("goToPageRowIndex()")
if ct.Views.Table.Backing() == nil {
return nil
}
cx, _ := ct.Views.Table.Backing().Cursor()
if err := ct.Views.Table.Backing().SetCursor(cx, idx); err != nil {
cx := ct.Views.Table.CursorX()
if err := ct.Views.Table.SetCursor(cx, idx); err != nil {
return err
}
ct.RowChanged()
@ -455,23 +401,19 @@ func (ct *Cointop) GoToGlobalIndex(idx int) error {
// HighlightRow highlights the row at index
func (ct *Cointop) HighlightRow(idx int) error {
ct.debuglog("highlightRow()")
if ct.Views.Table.Backing() == nil {
return nil
}
ct.Views.Table.Backing().SetOrigin(0, 0)
ct.Views.Table.Backing().SetCursor(0, 0)
ox, _ := ct.Views.Table.Backing().Origin()
cx, _ := ct.Views.Table.Backing().Cursor()
_, sy := ct.Views.Table.Backing().Size()
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()
perpage := ct.TotalPerPage()
p := idx % perpage
oy := (p / sy) * sy
cy := p % sy
if oy > 0 {
ct.Views.Table.Backing().SetOrigin(ox, oy)
ct.Views.Table.SetOrigin(ox, oy)
}
ct.Views.Table.Backing().SetCursor(cx, cy)
ct.Views.Table.SetCursor(cx, cy)
return nil
}

@ -11,19 +11,19 @@ import (
"strconv"
"strings"
"github.com/miguelmota/cointop/cointop/common/asciitable"
"github.com/miguelmota/cointop/cointop/common/humanize"
"github.com/miguelmota/cointop/cointop/common/pad"
"github.com/miguelmota/cointop/pkg/asciitable"
"github.com/miguelmota/cointop/pkg/humanize"
"github.com/miguelmota/cointop/pkg/pad"
"github.com/miguelmota/cointop/pkg/ui"
)
// PortfolioUpdateMenuView is structure for portfolio update menu view
type PortfolioUpdateMenuView struct {
*View
}
type PortfolioUpdateMenuView = ui.View
// NewPortfolioUpdateMenuView returns a new portfolio update menu view
func NewPortfolioUpdateMenuView() *PortfolioUpdateMenuView {
return &PortfolioUpdateMenuView{NewView("portfolioupdatemenu")}
var view *PortfolioUpdateMenuView = ui.NewView("portfolioupdatemenu")
return view
}
// TogglePortfolio toggles the portfolio view
@ -71,7 +71,7 @@ func (ct *Cointop) CoinHoldings(coin *Coin) float64 {
}
// UpdatePortfolioUpdateMenu updates the portfolio update menu view
func (ct *Cointop) UpdatePortfolioUpdateMenu() {
func (ct *Cointop) UpdatePortfolioUpdateMenu() error {
ct.debuglog("updatePortfolioUpdateMenu()")
coin := ct.HighlightedRowCoin()
exists := ct.PortfolioEntryExists(coin)
@ -92,14 +92,14 @@ func (ct *Cointop) UpdatePortfolioUpdateMenu() {
label := fmt.Sprintf(" Enter holdings for %s %s", ct.colorscheme.MenuLabel(coin.Name), current)
content := fmt.Sprintf("%s\n%s\n\n%s%s\n\n\n [Enter] %s [ESC] Cancel", header, label, strings.Repeat(" ", 29), coin.Symbol, submitText)
ct.Update(func() error {
ct.Views.PortfolioUpdateMenu.Backing().Clear()
ct.Views.PortfolioUpdateMenu.Backing().Frame = true
fmt.Fprintln(ct.Views.PortfolioUpdateMenu.Backing(), content)
fmt.Fprintln(ct.Views.Input.Backing(), value)
ct.Views.Input.Backing().SetCursor(len(value), 0)
ct.UpdateUI(func() error {
ct.Views.PortfolioUpdateMenu.SetFrame(true)
ct.Views.PortfolioUpdateMenu.Update(content)
ct.Views.Input.Write(value)
ct.Views.Input.SetCursor(len(value), 0)
return nil
})
return nil
}
// ShowPortfolioUpdateMenu shows the portfolio update menu
@ -122,20 +122,13 @@ func (ct *Cointop) ShowPortfolioUpdateMenu() error {
func (ct *Cointop) HidePortfolioUpdateMenu() error {
ct.debuglog("hidePortfolioUpdateMenu()")
ct.State.portfolioUpdateMenuVisible = false
ct.SetViewOnBottom(ct.Views.PortfolioUpdateMenu.Name())
ct.SetViewOnBottom(ct.Views.Input.Name())
ct.ui.SetViewOnBottom(ct.Views.PortfolioUpdateMenu)
ct.ui.SetViewOnBottom(ct.Views.Input)
ct.SetActiveView(ct.Views.Table.Name())
ct.Update(func() error {
if ct.Views.PortfolioUpdateMenu.Backing() == nil {
return nil
}
ct.Views.PortfolioUpdateMenu.Backing().Clear()
ct.Views.PortfolioUpdateMenu.Backing().Frame = false
fmt.Fprintln(ct.Views.PortfolioUpdateMenu.Backing(), "")
ct.Views.Input.Backing().Clear()
fmt.Fprintln(ct.Views.Input.Backing(), "")
ct.UpdateUI(func() error {
ct.Views.PortfolioUpdateMenu.SetFrame(false)
ct.Views.PortfolioUpdateMenu.Update("")
ct.Views.Input.Update("")
return nil
})
@ -150,7 +143,7 @@ func (ct *Cointop) SetPortfolioHoldings() error {
// read input field
b := make([]byte, 100)
n, err := ct.Views.Input.Backing().Read(b)
n, err := ct.Views.Input.Read(b)
if err != nil {
return err
}

@ -3,8 +3,8 @@ package cointop
import (
"fmt"
"github.com/miguelmota/cointop/cointop/common/api"
"github.com/miguelmota/cointop/cointop/common/humanize"
"github.com/miguelmota/cointop/pkg/api"
"github.com/miguelmota/cointop/pkg/humanize"
)
// PriceConfig is the config options for the price command

@ -22,7 +22,7 @@ func (ct *Cointop) QuitView() error {
ct.State.filterByFavorites = false
return ct.UpdateTable()
}
if ct.ActiveViewName() == ct.Views.Table.Name() {
if ct.ui.ActiveViewName() == ct.Views.Table.Name() {
return ct.Quit()
}

@ -4,27 +4,26 @@ import (
"regexp"
"strings"
"github.com/miguelmota/cointop/cointop/common/levenshtein"
"github.com/miguelmota/cointop/pkg/levenshtein"
"github.com/miguelmota/cointop/pkg/ui"
)
// SearchFieldView is structure for search field view
type SearchFieldView struct {
*View
}
type SearchFieldView = ui.View
// NewSearchFieldView returns a new search field view
func NewSearchFieldView() *SearchFieldView {
return &SearchFieldView{NewView("searchfield")}
var view *SearchFieldView = ui.NewView("searchfield")
return view
}
// InputView is structure for help view
type InputView struct {
*View
}
type InputView = ui.View
// NewInputView returns a new help view
func NewInputView() *InputView {
return &InputView{NewView("input")}
var view *InputView = ui.NewView("input")
return view
}
// OpenSearch opens the search field
@ -46,9 +45,12 @@ func (ct *Cointop) CancelSearch() error {
// DoSearch triggers the search and sets views
func (ct *Cointop) DoSearch() error {
ct.debuglog("doSearch()")
ct.Views.SearchField.Backing().Rewind()
ct.Views.SearchField.Rewind()
b := make([]byte, 100)
n, err := ct.Views.SearchField.Backing().Read(b)
n, err := ct.Views.SearchField.Read(b)
if err != nil {
return err
}
// TODO: do this a better way (SoC)
ct.State.filterByFavorites = false

@ -3,30 +3,18 @@ package cointop
import (
"fmt"
"github.com/miguelmota/cointop/cointop/common/open"
"github.com/miguelmota/cointop/cointop/common/pad"
"github.com/miguelmota/cointop/pkg/open"
"github.com/miguelmota/cointop/pkg/pad"
"github.com/miguelmota/cointop/pkg/ui"
)
// StatusbarView is structure for statusbar view
type StatusbarView struct {
*View
}
type StatusbarView = ui.View
// NewStatusbarView returns a new statusbar view
func NewStatusbarView() *StatusbarView {
return &StatusbarView{NewView("statusbar")}
}
// Update updates the content of the statusbar
func (statusbar *StatusbarView) Update(str string) error {
if statusbar.Backing() == nil {
return nil
}
statusbar.Backing().Clear()
fmt.Fprintln(statusbar.Backing(), str)
return nil
var view *StatusbarView = ui.NewView("statusbar")
return view
}
// UpdateStatusbar updates the statusbar view
@ -63,9 +51,8 @@ func (ct *Cointop) UpdateStatusbar(s string) error {
str = str[:end] + v
ct.Update(func() error {
ct.Views.Statusbar.Update(str)
return nil
ct.UpdateUI(func() error {
return ct.Views.Statusbar.Update(str)
})
return nil

@ -8,19 +8,19 @@ import (
"strings"
"time"
"github.com/miguelmota/cointop/cointop/common/humanize"
"github.com/miguelmota/cointop/cointop/common/pad"
"github.com/miguelmota/cointop/cointop/common/table"
"github.com/miguelmota/cointop/pkg/humanize"
"github.com/miguelmota/cointop/pkg/pad"
"github.com/miguelmota/cointop/pkg/table"
"github.com/miguelmota/cointop/pkg/ui"
)
// TableView is structure for table view
type TableView struct {
*View
}
type TableView = ui.View
// NewTableView returns a new table view
func NewTableView() *TableView {
return &TableView{NewView("table")}
var view *TableView = ui.NewView("table")
return view
}
// TableColumnOrder returns the default order of the table columns
@ -193,12 +193,8 @@ func (ct *Cointop) RefreshTable() error {
ct.HighlightRow(currentrow)
}
ct.Update(func() error {
if ct.Views.Table.Backing() == nil {
return nil
}
ct.Views.Table.Backing().Clear()
ct.UpdateUI(func() error {
ct.Views.Table.Clear()
ct.table.Format().Fprint(ct.Views.Table.Backing())
go ct.RowChanged()
go ct.UpdateTableHeader()
@ -288,13 +284,9 @@ func (ct *Cointop) GetTableCoinsSlice() []*Coin {
// HighlightedRowIndex returns the index of the highlighted row
func (ct *Cointop) HighlightedRowIndex() int {
ct.debuglog("HighlightedRowIndex()")
if ct.Views.Table.Backing() == nil {
return 0
}
_, y := ct.Views.Table.Backing().Origin()
_, cy := ct.Views.Table.Backing().Cursor()
idx := y + cy
oy := ct.Views.Table.OriginY()
cy := ct.Views.Table.CursorY()
idx := oy + cy
if idx < 0 {
idx = 0
}
@ -317,7 +309,7 @@ func (ct *Cointop) HighlightedRowCoin() *Coin {
// HighlightedPageRowIndex returns the index of page row of the highlighted row
func (ct *Cointop) HighlightedPageRowIndex() int {
ct.debuglog("HighlightedPageRowIndex()")
_, cy := ct.Views.Table.Backing().Cursor()
cy := ct.Views.Table.CursorY()
idx := cy
if idx < 0 {
idx = 0

@ -3,20 +3,21 @@ package cointop
import (
"fmt"
"strings"
"github.com/miguelmota/cointop/pkg/ui"
)
// TableHeaderView is structure for table header view
type TableHeaderView struct {
*View
}
type TableHeaderView = ui.View
// NewTableHeaderView returns a new table header view
func NewTableHeaderView() *TableHeaderView {
return &TableHeaderView{NewView("header")}
var view *TableHeaderView = ui.NewView("table_header")
return view
}
// UpdateTableHeader renders the table header
func (ct *Cointop) UpdateTableHeader() {
func (ct *Cointop) UpdateTableHeader() error {
ct.debuglog("UpdateTableHeader()")
var cols []string
@ -89,13 +90,9 @@ func (ct *Cointop) UpdateTableHeader() {
headers = append(headers, str)
}
ct.Update(func() error {
if ct.Views.TableHeader.Backing() == nil {
return nil
}
ct.Views.TableHeader.Backing().Clear()
fmt.Fprintln(ct.Views.TableHeader.Backing(), strings.Join(headers, ""))
return nil
ct.UpdateUI(func() error {
return ct.Views.TableHeader.Update(strings.Join(headers, ""))
})
return nil
}

@ -6,9 +6,9 @@ import (
"github.com/miguelmota/gocui"
)
// Update takes a callback which updates the view
func (ct *Cointop) Update(f func() error) {
ct.debuglog(fmt.Sprintf("Update()"))
// UpdateUI takes a callback which updates the view
func (ct *Cointop) UpdateUI(f func() error) {
ct.debuglog(fmt.Sprintf("UpdateUI()"))
if ct.g == nil {
return

@ -5,7 +5,7 @@ import (
"encoding/gob"
"strings"
"github.com/miguelmota/cointop/cointop/common/open"
"github.com/miguelmota/cointop/pkg/open"
)
// OpenLink opens the url in a browser

@ -1,83 +0,0 @@
package cointop
import (
"fmt"
"github.com/miguelmota/gocui"
)
// IView is a cointop view
type IView interface {
Backing() *gocui.View
SetBacking(gocuiView *gocui.View)
Name() string
}
// View is a cointop view
type View struct {
backing *gocui.View
name string
}
// NewView creates a new view
func NewView(name string) *View {
return &View{
name: name,
}
}
// Backing returns the backing gocui view
func (view *View) Backing() *gocui.View {
return view.backing
}
// SetBacking sets the backing gocui view
func (view *View) SetBacking(gocuiView *gocui.View) {
view.backing = gocuiView
}
// Height returns the view height
func (view *View) Height() int {
_, h := view.backing.Size()
return h
}
// Width returns the view width
func (view *View) Width() int {
w, _ := view.backing.Size()
return w
}
// Name returns the view's name
func (view *View) Name() string {
return view.name
}
// SetActiveView sets the active view
func (ct *Cointop) SetActiveView(v string) error {
ct.g.SetViewOnTop(v)
ct.g.SetCurrentView(v)
if v == ct.Views.SearchField.Name() {
ct.Views.SearchField.Backing().Clear()
ct.Views.SearchField.Backing().SetCursor(1, 0)
fmt.Fprintf(ct.Views.SearchField.Backing(), "%s", "/")
} else if v == ct.Views.Table.Name() {
ct.g.SetViewOnTop(ct.Views.Statusbar.Name())
}
if v == ct.Views.PortfolioUpdateMenu.Name() {
ct.g.SetViewOnTop(ct.Views.Input.Name())
ct.g.SetCurrentView(ct.Views.Input.Name())
}
return nil
}
// ActiveViewName returns the name of the active view
func (ct *Cointop) ActiveViewName() string {
return ct.g.CurrentView().Name()
}
// SetViewOnBottom sets the view to the bottom layer
func (ct *Cointop) SetViewOnBottom(v string) error {
_, err := ct.g.SetViewOnBottom(v)
return err
}

@ -1,7 +1,7 @@
package main
import (
"github.com/miguelmota/cointop/cointop/cmd"
cmd "github.com/miguelmota/cointop/cmd/commands"
)
func main() {

@ -1,8 +1,8 @@
package api
import (
cg "github.com/miguelmota/cointop/cointop/common/api/impl/coingecko"
cmc "github.com/miguelmota/cointop/cointop/common/api/impl/coinmarketcap"
cg "github.com/miguelmota/cointop/pkg/api/impl/coingecko"
cmc "github.com/miguelmota/cointop/pkg/api/impl/coinmarketcap"
)
// NewCMC new CoinMarketCap API

@ -7,10 +7,10 @@ import (
"strings"
"time"
gecko "github.com/miguelmota/cointop/cointop/api/coingecko/v3"
geckoTypes "github.com/miguelmota/cointop/cointop/api/coingecko/v3/types"
apitypes "github.com/miguelmota/cointop/cointop/common/api/types"
util "github.com/miguelmota/cointop/cointop/common/api/util"
apitypes "github.com/miguelmota/cointop/pkg/api/types"
util "github.com/miguelmota/cointop/pkg/api/util"
gecko "github.com/miguelmota/cointop/pkg/api/vendors/coingecko/v3"
geckoTypes "github.com/miguelmota/cointop/pkg/api/vendors/coingecko/v3/types"
)
// ErrPingFailed is the error for when pinging the API fails

@ -7,8 +7,8 @@ import (
"strings"
"time"
apitypes "github.com/miguelmota/cointop/cointop/common/api/types"
util "github.com/miguelmota/cointop/cointop/common/api/util"
apitypes "github.com/miguelmota/cointop/pkg/api/types"
util "github.com/miguelmota/cointop/pkg/api/util"
cmc "github.com/miguelmota/go-coinmarketcap/pro/v1"
cmcv2 "github.com/miguelmota/go-coinmarketcap/v2"
)

@ -1,7 +1,7 @@
package api
import (
types "github.com/miguelmota/cointop/cointop/common/api/types"
types "github.com/miguelmota/cointop/pkg/api/types"
)
// Interface interface

@ -9,8 +9,8 @@ import (
"net/url"
"strings"
"github.com/miguelmota/cointop/cointop/api/coingecko/format"
"github.com/miguelmota/cointop/cointop/api/coingecko/v3/types"
"github.com/miguelmota/cointop/pkg/api/vendors/coingecko/format"
"github.com/miguelmota/cointop/pkg/api/vendors/coingecko/v3/types"
)
var baseURL = "https://api.coingecko.com/api/v3"

@ -0,0 +1,84 @@
package chartplot
import (
"github.com/miguelmota/cointop/pkg/termui"
)
// ChartPlot ...
type ChartPlot struct {
t *termui.LineChart
}
// NewChartPlot ...
func NewChartPlot() *ChartPlot {
t := termui.NewLineChart()
// NOTE: empty list means don't show x-axis labels
t.DataLabels = []string{""}
t.Border = false
return &ChartPlot{
t: t,
}
}
// Height ...
func (c *ChartPlot) Height() int {
return c.t.Height
}
// SetHeight ...
func (c *ChartPlot) SetHeight(height int) {
c.t.Height = height
}
// Width ...
func (c *ChartPlot) Width() int {
return c.t.Width
}
// SetWidth ...
func (c *ChartPlot) SetWidth(width int) {
c.t.Width = width
}
// SetBorder ...
func (c *ChartPlot) SetBorder(enabled bool) {
c.t.Border = enabled
}
// SetData ...
func (c *ChartPlot) SetData(data []float64) {
// NOTE: edit `termui.LineChart.shortenFloatVal(float64)` to not
// use exponential notation.
c.t.Data = data
}
// GetChartPoints ...
func (c *ChartPlot) GetChartPoints(width int) [][]rune {
termui.Body = termui.NewGrid()
termui.Body.Width = width
termui.Body.AddRows(
termui.NewRow(
termui.NewCol(12, 0, c.t),
),
)
var points [][]rune
// calculate layout
termui.Body.Align()
w := termui.Body.Width
h := c.Height()
row := termui.Body.Rows[0]
b := row.Buffer()
for i := 0; i < h; i = i + 1 {
var rowpoints []rune
for j := 0; j < w; j = j + 1 {
p := b.At(j, i)
rowpoints = append(rowpoints, p.Ch)
}
points = append(points, rowpoints)
}
return points
}

@ -16,7 +16,7 @@ import (
"github.com/creack/pty"
"github.com/gliderlabs/ssh"
"github.com/miguelmota/cointop/cointop/common/pathutil"
"github.com/miguelmota/cointop/pkg/pathutil"
gossh "golang.org/x/crypto/ssh"
)

@ -6,7 +6,7 @@ import (
"sort"
"strings"
"github.com/miguelmota/cointop/cointop/common/table/align"
"github.com/miguelmota/cointop/pkg/table/align"
)
// Table table

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save