From 9abe9905d799e7fd3dbb5d69733c9fa0a97e7880 Mon Sep 17 00:00:00 2001 From: Gustavo Chain Date: Fri, 14 Feb 2020 13:55:08 +0100 Subject: [PATCH] ui refactor --- ui/blocks.go | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ ui/ui.go | 99 +++++++++-------------------------------------- 2 files changed, 125 insertions(+), 80 deletions(-) create mode 100644 ui/blocks.go diff --git a/ui/blocks.go b/ui/blocks.go new file mode 100644 index 0000000..c0766d1 --- /dev/null +++ b/ui/blocks.go @@ -0,0 +1,106 @@ +package ui + +import ( + "bytes" + "fmt" + "strings" + "time" + + "github.com/fatih/color" + "github.com/gchaincl/mempool/client" +) + +type Box struct { + x int + lines []string +} + +func (b *Box) Printf(c color.Attribute, f string, args ...interface{}) *Box { + s := b.center(fmt.Sprintf(f, args...)) + s = color.New(c).Sprint(s) + b.lines = append(b.lines, s) + return b +} + +func (b *Box) Append(s string) *Box { + b.lines = append(b.lines, b.center(s)) + return b +} + +func (b *Box) center(line string) string { + l := len(line) + if l > b.x { + return line + } + offset := strings.Repeat(" ", (b.x-l)/2) + return fmt.Sprintf("%s%s%s", offset, line, offset) +} + +func (b *Box) Render(full int, bg color.Attribute) []byte { + buf := bytes.NewBuffer(nil) + fn := color.New(bg).SprintfFunc() + for i, s := range b.lines { + if 9-full <= i { + s = fn("%s", s) + } + fmt.Fprintln(buf, s) + } + return buf.Bytes() +} + +type ProjectedBlock client.ProjectedBlock + +func (b ProjectedBlock) Print(n int, x, _y int) []byte { + var footer string + // Attach ETA to the first 3 blocks + if n < 3 { + footer = fmt.Sprintf("in ~%d minutes", (n+1)*10) + } else { + n := ceil(float64(b.BlockWeight) / 4000000.0) + footer = fmt.Sprintf("+%d blocks", n) + } + + box := &Box{x: x} + box.Printf(color.FgWhite, "~%d sat/vB", ceil(b.MedianFee)). + Printf(color.FgYellow, "%d-%d sat/vB", ceil(b.MinFee), ceil(b.MaxFee)). + Append(""). + Printf(color.FgWhite, "%.2f MB", float64(b.BlockSize)/(1000*1000)). + Printf(color.FgWhite, "%4d transactions", b.NTx). + Append(""). + Append(""). + Append(""). + Printf(color.FgWhite, footer) + + // calculate how full is the block + var full int + if n < 3 { + full = int( + float64(b.BlockWeight) / 4000000 * 10, + ) + } + + return box.Render(full, color.BgRed) +} + +type Block client.Block + +func (b Block) Print(n int, x, _y int) []byte { + ago := time.Now().Unix() - int64(b.Time) + box := &Box{x: x} + + box.Printf(color.FgWhite, "~%d sat/Vb", ceil(b.MedianFee)). + Printf(color.FgYellow, "%d-%d sat/vB", ceil(b.MinFee), ceil(b.MaxFee)). + Append(""). + Printf(color.FgWhite, "%.2f MB", float64(b.Size)/(1000*1000)). + Printf(color.FgWhite, " %4d transactions", b.NTx). + Append(""). + Append(""). + Append(""). + Printf(color.FgWhite, "%s ago", fmtSeconds(ago)) + + full := int( + float64(b.Weight) / 4000000 * 10, + ) + + return box.Render(full+4, color.BgBlue) +} diff --git a/ui/ui.go b/ui/ui.go index dceaa0a..e83c23d 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -1,11 +1,9 @@ package ui import ( - "bytes" "fmt" "math" "strings" - "time" "github.com/fatih/color" "github.com/gchaincl/mempool/client" @@ -121,7 +119,8 @@ func (ui *UI) Layout(g *gocui.Gui) error { v.BgColor = gocui.ColorBlack } v.Clear() - if _, err := v.Write(ui.printProjectedBlock(i)); err != nil { + + if _, err := v.Write(ui.printProjectedBlock(i, x1-x0, y1-y0)); err != nil { return err } } @@ -155,7 +154,7 @@ func (ui *UI) Layout(g *gocui.Gui) error { } v.Title = fmt.Sprintf("#%d", block.Height) v.Clear() - if _, err := v.Write(ui.printBlock(i)); err != nil { + if _, err := v.Write(ui.printBlock(i, x1-x0, y1-y0)); err != nil { return err } } @@ -167,6 +166,16 @@ func (ui *UI) Layout(g *gocui.Gui) error { return nil } +func (ui *UI) printProjectedBlock(n int, x, y int) []byte { + b := ui.state.projected[n] + return ProjectedBlock(b).Print(n, x, y) +} + +func (ui *UI) printBlock(n int, x, y int) []byte { + b := ui.state.blocks[n] + return Block(b).Print(n, x, y) +} + func (ui *UI) separator(g *gocui.Gui, x, y int, vertical bool) error { var x0, x1, y0, y1 int if vertical { @@ -196,14 +205,13 @@ func (ui *UI) separator(g *gocui.Gui, x, y int, vertical bool) error { return nil } -var ( - white = color.New(color.FgWhite).SprintfFunc() - yellow = color.New(color.FgYellow).SprintfFunc() - red = color.New(color.FgRed).SprintfFunc() - blue = color.New(color.FgBlue).SprintfFunc() -) - func (ui *UI) info(g *gocui.Gui, x, y int) error { + var ( + white = color.New(color.FgWhite).SprintfFunc() + red = color.New(color.FgRed).SprintfFunc() + blue = color.New(color.FgBlue).SprintfFunc() + ) + v, err := g.SetView("info", 0, y-2, x, y) if err != nil { if err != gocui.ErrUnknownView { @@ -236,75 +244,6 @@ func ceil(f float64) int { ) } -func (ui *UI) printProjectedBlock(n int) []byte { - block := ui.state.projected[n] - - lines := []string{ - white(" ~%d sat/vB ", ceil(block.MedianFee)), - yellow(" %d - %d sat/vB ", ceil(block.MinFee), ceil(block.MaxFee)), - " ", - white(" %.2f MB ", float64(block.BlockSize)/(1000*1000)), - white(" %4d transactions ", block.NTx), - " ", - " ", - " ", - " ", - " ", - } - - if n < 3 { - lines[8] = white(" in ~%2d minutes ", (n+1)*10) - bg := color.New(color.BgRed).SprintfFunc() - offset := 9 - int( - float64(block.BlockWeight)/4000000.0*10, - ) - if offset < 0 { - offset = 0 - } - - for i := offset; i < len(lines); i++ { - lines[i] = bg("%s", lines[i]) - } - } else { - bw := math.Ceil(float64(block.BlockWeight) / 4000000.0) - lines[8] = white(" +%d blocks", int(bw)) - } - - buf := bytes.NewBuffer(nil) - fmt.Fprintf(buf, strings.Join(lines, "\n")) - return buf.Bytes() -} - -func (ui *UI) printBlock(n int) []byte { - block := ui.state.blocks[n] - - ago := time.Now().Unix() - int64(block.Time) - lines := []string{ - white(" ~%d sat/Vb ", ceil(block.MedianFee)), - yellow(" %d - %d sat/vB ", ceil(block.MinFee), ceil(block.MaxFee)), - " ", - white(" %.2f MB ", float64(block.Size)/(1000*1000)), - white(" %4d transactions ", block.NTx), - " ", - " ", - " ", - white(" %s ago ", fmtSeconds(ago)), - " ", - } - - bg := color.New(color.BgBlue).SprintfFunc() - offset := 9 - int( - float64(block.Weight)/4000000.0*10, - ) - for i := offset; i < len(lines); i++ { - lines[i] = bg("%s", lines[i]) - } - - buf := bytes.NewBuffer(nil) - fmt.Fprintf(buf, strings.Join(lines, "\n")) - return buf.Bytes() -} - func fmtSeconds(s int64) string { if s < 60 { return "< 1 minute"