add intro page and storage initialization

This commit is contained in:
sqshq 2019-05-20 00:12:40 -04:00
parent 8fa382e37d
commit 911be1ba00
15 changed files with 366 additions and 60 deletions

8
client/backend.go Normal file
View File

@ -0,0 +1,8 @@
package client
import "github.com/sqshq/sampler/storage"
// TODO
func loadLicense(key string) *storage.License {
return nil
}

View File

@ -44,7 +44,7 @@ func RenderAlert(alert *data.Alert, area image.Rectangle, buffer *ui.Buffer) {
} }
block := *ui.NewBlock() block := *ui.NewBlock()
block.SetRect(getRectCoordinates(area, width, len(lines))) block.SetRect(util.GetRectCoordinates(area, width, len(lines)))
block.BorderStyle = ui.Style{Fg: color, Bg: ui.ColorClear} block.BorderStyle = ui.Style{Fg: color, Bg: ui.ColorClear}
block.Draw(buffer) block.Draw(buffer)
@ -52,13 +52,6 @@ func RenderAlert(alert *data.Alert, area image.Rectangle, buffer *ui.Buffer) {
for i := 0; i < len(lines); i++ { for i := 0; i < len(lines); i++ {
buffer.SetString(lines[i], buffer.SetString(lines[i],
ui.NewStyle(color), getMiddlePoint(block.Inner, lines[i], i-1)) ui.NewStyle(color), util.GetMiddlePoint(block.Inner, lines[i], i-1))
} }
} }
// TODO move to utils
func getRectCoordinates(area image.Rectangle, width int, height int) (int, int, int, int) {
x1 := area.Min.X + area.Dx()/2 - width/2
y1 := area.Min.Y + area.Dy()/2 - height
return x1, y1, x1 + width, y1 + height + 2
}

139
component/intro.go Normal file
View File

@ -0,0 +1,139 @@
package component
import (
ui "github.com/gizak/termui/v3"
"github.com/sqshq/sampler/component/util"
"github.com/sqshq/sampler/console"
)
type Intro struct {
*ui.Block
page IntroPage
option introOption
palette console.Palette
}
type IntroPage rune
const (
IntroPageWelcome IntroPage = 0
IntroPageCommercial IntroPage = 1
IntroPagePersonal IntroPage = 2
)
type introOption rune
const (
introOptionCommercial introOption = 0
introOptionPersonal introOption = 1
)
const (
buttonCommercial string = " COMMERCIAL USE "
buttonPersonal string = " PERSONAL USE "
buttonOk string = " OK "
)
func (intro *Intro) Up() {
intro.option = introOptionCommercial
}
func (intro *Intro) Down() {
intro.option = introOptionPersonal
}
func (intro *Intro) NextPage() {
if intro.option == introOptionCommercial {
intro.page = IntroPageCommercial
} else {
intro.page = IntroPagePersonal
}
}
func (intro *Intro) GetSelectedPage() IntroPage {
return intro.page
}
func NewIntro(palette console.Palette) *Intro {
return &Intro{
Block: NewBlock("", false, palette),
palette: palette,
}
}
func (intro *Intro) Draw(buffer *ui.Buffer) {
logo := []string{
" __ ",
" _________ ____ ___ ____ / /__ _____",
" / ___/ __ `/ __ `__ \\/ __ \\/ / _ \\/ ___/",
" (__ ) /_/ / / / / / / /_/ / / __/ / ",
"/____/\\__,_/_/ /_/ /_/ .___/_/\\___/_/ ",
" /_/ ",
}
introText := append(logo, []string{
"", "", "",
"Welcome.",
"Sampler is free of charge for personal use, but license must be purchased to use it for business purposes.",
"Clicking below indicates you agree to the terms of the license agreement and privacy policy: www.sampler.dev/license",
"", "", "",
"How do you plan to use Sampler?",
}...)
commericalText := append(logo, []string{
"", "", "", "",
"Please visit www.sampler.dev to purchase a license and then start Sampler with --license flag",
}...)
personalText := append(logo, []string{
"", "", "", "",
"Sampler is always free for non-commercial use, but you can support the project and buy a personal license:",
"www.sampler.dev",
}...)
text := introText
switch intro.page {
case IntroPageWelcome:
text = introText
case IntroPageCommercial:
text = commericalText
case IntroPagePersonal:
text = personalText
}
for i, a := range text {
util.PrintString(
a,
ui.NewStyle(intro.palette.BaseColor),
util.GetMiddlePoint(intro.Block.Rectangle, a, i-15),
buffer)
}
highlightedStyle := ui.NewStyle(intro.palette.ReverseColor, intro.palette.BaseColor)
regularStyle := ui.NewStyle(intro.palette.BaseColor, intro.palette.ReverseColor)
if intro.page == IntroPageWelcome {
commercialButtonStyle := highlightedStyle
if intro.option == introOptionPersonal {
commercialButtonStyle = regularStyle
}
personalButtonStyle := highlightedStyle
if intro.option == introOptionCommercial {
personalButtonStyle = regularStyle
}
buffer.SetString(string(buttonCommercial), commercialButtonStyle,
util.GetMiddlePoint(intro.Block.Rectangle, string(buttonCommercial), 6))
buffer.SetString(string(buttonPersonal), personalButtonStyle,
util.GetMiddlePoint(intro.Block.Rectangle, string(buttonPersonal), 8))
} else {
buffer.SetString(string(buttonOk), highlightedStyle,
util.GetMiddlePoint(intro.Block.Rectangle, string(buttonOk), 4))
}
intro.Block.Draw(buffer)
}

View File

@ -4,6 +4,7 @@ import (
ui "github.com/gizak/termui/v3" ui "github.com/gizak/termui/v3"
"github.com/sqshq/sampler/component" "github.com/sqshq/sampler/component"
"github.com/sqshq/sampler/component/runchart" "github.com/sqshq/sampler/component/runchart"
"github.com/sqshq/sampler/component/util"
"github.com/sqshq/sampler/config" "github.com/sqshq/sampler/config"
"github.com/sqshq/sampler/console" "github.com/sqshq/sampler/console"
"github.com/sqshq/sampler/data" "github.com/sqshq/sampler/data"
@ -16,6 +17,7 @@ type Layout struct {
Components []*component.Component Components []*component.Component
statusbar *component.StatusBar statusbar *component.StatusBar
menu *component.Menu menu *component.Menu
intro *component.Intro
ChangeModeEvents chan Mode ChangeModeEvents chan Mode
mode Mode mode Mode
selection int selection int
@ -25,12 +27,13 @@ type Mode rune
const ( const (
ModeDefault Mode = 0 ModeDefault Mode = 0
ModePause Mode = 1 ModeIntro Mode = 1
ModeComponentSelect Mode = 2 ModePause Mode = 2
ModeMenuOptionSelect Mode = 3 ModeComponentSelect Mode = 3
ModeComponentMove Mode = 4 ModeMenuOptionSelect Mode = 4
ModeComponentResize Mode = 5 ModeComponentMove Mode = 5
ModeChartPinpoint Mode = 6 ModeComponentResize Mode = 6
ModeChartPinpoint Mode = 7
) )
const ( const (
@ -38,10 +41,11 @@ const (
statusbarHeight = 1 statusbarHeight = 1
) )
func NewLayout(width, height int, statusline *component.StatusBar, menu *component.Menu) *Layout { func NewLayout(width, height int, statusline *component.StatusBar, menu *component.Menu, intro *component.Intro) *Layout {
block := *ui.NewBlock() block := *ui.NewBlock()
block.SetRect(0, 0, width, height) block.SetRect(0, 0, width, height)
intro.SetRect(0, 0, width, height)
statusline.SetRect(0, height-statusbarHeight, width, height) statusline.SetRect(0, height-statusbarHeight, width, height)
return &Layout{ return &Layout{
@ -49,6 +53,7 @@ func NewLayout(width, height int, statusline *component.StatusBar, menu *compone
Components: make([]*component.Component, 0), Components: make([]*component.Component, 0),
statusbar: statusline, statusbar: statusline,
menu: menu, menu: menu,
intro: intro,
mode: ModeDefault, mode: ModeDefault,
selection: 0, selection: 0,
ChangeModeEvents: make(chan Mode, 10), ChangeModeEvents: make(chan Mode, 10),
@ -59,12 +64,19 @@ func (l *Layout) AddComponent(cpt *component.Component) {
l.Components = append(l.Components, cpt) l.Components = append(l.Components, cpt)
} }
func (l *Layout) RunIntro() {
l.mode = ModeIntro
}
func (l *Layout) changeMode(m Mode) { func (l *Layout) changeMode(m Mode) {
l.mode = m l.mode = m
l.ChangeModeEvents <- m l.ChangeModeEvents <- m
} }
func (l *Layout) HandleMouseClick(x int, y int) { func (l *Layout) HandleMouseClick(x int, y int) {
if l.mode == ModeIntro {
return
}
l.menu.Idle() l.menu.Idle()
selected, i := l.findComponentAtPoint(image.Point{X: x, Y: y}) selected, i := l.findComponentAtPoint(image.Point{X: x, Y: y})
if selected == nil { if selected == nil {
@ -118,6 +130,14 @@ func (l *Layout) HandleKeyboardEvent(e string) {
case ModeComponentResize: case ModeComponentResize:
l.menu.Idle() l.menu.Idle()
l.changeMode(ModeDefault) l.changeMode(ModeDefault)
break
case ModeIntro:
page := l.intro.GetSelectedPage()
if page == component.IntroPageWelcome {
l.intro.NextPage()
} else {
l.changeMode(ModeDefault)
}
} }
case console.KeyEsc: case console.KeyEsc:
l.resetAlerts() l.resetAlerts()
@ -180,6 +200,8 @@ func (l *Layout) HandleKeyboardEvent(e string) {
selected.Move(0, -1) selected.Move(0, -1)
case ModeComponentResize: case ModeComponentResize:
selected.Resize(0, -1) selected.Resize(0, -1)
case ModeIntro:
l.intro.Up()
} }
case console.KeyDown: case console.KeyDown:
switch l.mode { switch l.mode {
@ -195,6 +217,8 @@ func (l *Layout) HandleKeyboardEvent(e string) {
selected.Move(0, 1) selected.Move(0, 1)
case ModeComponentResize: case ModeComponentResize:
selected.Resize(0, 1) selected.Resize(0, 1)
case ModeIntro:
l.intro.Down()
} }
} }
} }
@ -232,21 +256,21 @@ func (l *Layout) moveSelection(direction string) {
switch direction { switch direction {
case console.KeyLeft: case console.KeyLeft:
previouslySelectedCornerPoint = component.GetRectLeftSideCenter(previouslySelected.GetRect()) previouslySelectedCornerPoint = util.GetRectLeftSideCenter(previouslySelected.GetRect())
newlySelectedCornerPoint = component.GetRectRightSideCenter(l.getComponent(newlySelectedIndex).GetRect()) newlySelectedCornerPoint = util.GetRectRightSideCenter(l.getComponent(newlySelectedIndex).GetRect())
currentCornerPoint = component.GetRectRightSideCenter(current.GetRect()) currentCornerPoint = util.GetRectRightSideCenter(current.GetRect())
case console.KeyRight: case console.KeyRight:
previouslySelectedCornerPoint = component.GetRectRightSideCenter(previouslySelected.GetRect()) previouslySelectedCornerPoint = util.GetRectRightSideCenter(previouslySelected.GetRect())
newlySelectedCornerPoint = component.GetRectLeftSideCenter(l.getComponent(newlySelectedIndex).GetRect()) newlySelectedCornerPoint = util.GetRectLeftSideCenter(l.getComponent(newlySelectedIndex).GetRect())
currentCornerPoint = component.GetRectLeftSideCenter(current.GetRect()) currentCornerPoint = util.GetRectLeftSideCenter(current.GetRect())
case console.KeyUp: case console.KeyUp:
previouslySelectedCornerPoint = component.GetRectTopSideCenter(previouslySelected.GetRect()) previouslySelectedCornerPoint = util.GetRectTopSideCenter(previouslySelected.GetRect())
newlySelectedCornerPoint = component.GetRectBottomSideCenter(l.getComponent(newlySelectedIndex).GetRect()) newlySelectedCornerPoint = util.GetRectBottomSideCenter(l.getComponent(newlySelectedIndex).GetRect())
currentCornerPoint = component.GetRectBottomSideCenter(current.GetRect()) currentCornerPoint = util.GetRectBottomSideCenter(current.GetRect())
case console.KeyDown: case console.KeyDown:
previouslySelectedCornerPoint = component.GetRectBottomSideCenter(previouslySelected.GetRect()) previouslySelectedCornerPoint = util.GetRectBottomSideCenter(previouslySelected.GetRect())
newlySelectedCornerPoint = component.GetRectTopSideCenter(l.getComponent(newlySelectedIndex).GetRect()) newlySelectedCornerPoint = util.GetRectTopSideCenter(l.getComponent(newlySelectedIndex).GetRect())
currentCornerPoint = component.GetRectTopSideCenter(current.GetRect()) currentCornerPoint = util.GetRectTopSideCenter(current.GetRect())
} }
switch direction { switch direction {
@ -279,6 +303,12 @@ func (l *Layout) Draw(buffer *ui.Buffer) {
columnWidth := float64(l.GetRect().Dx()) / float64(console.ColumnsCount) columnWidth := float64(l.GetRect().Dx()) / float64(console.ColumnsCount)
rowHeight := float64(l.GetRect().Dy()-statusbarHeight) / float64(console.RowsCount) rowHeight := float64(l.GetRect().Dy()-statusbarHeight) / float64(console.RowsCount)
if l.mode == ModeIntro {
l.intro.SetRect(l.Min.X, l.Min.Y, l.Max.X, l.Max.Y)
l.intro.Draw(buffer)
return
}
for _, c := range l.Components { for _, c := range l.Components {
rectangle := calculateComponentCoordinates(c, columnWidth, rowHeight) rectangle := calculateComponentCoordinates(c, columnWidth, rowHeight)
c.SetRect(rectangle.Min.X, rectangle.Min.Y, rectangle.Max.X, rectangle.Max.Y) c.SetRect(rectangle.Min.X, rectangle.Min.Y, rectangle.Max.X, rectangle.Max.Y)

View File

@ -2,6 +2,7 @@ package component
import ( import (
ui "github.com/gizak/termui/v3" ui "github.com/gizak/termui/v3"
"github.com/sqshq/sampler/component/util"
"github.com/sqshq/sampler/config" "github.com/sqshq/sampler/config"
"github.com/sqshq/sampler/console" "github.com/sqshq/sampler/console"
"image" "image"
@ -130,14 +131,14 @@ func (m *Menu) renderHighlight(buffer *ui.Buffer) {
buffer.SetString( buffer.SetString(
optionsText, optionsText,
ui.NewStyle(console.ColorDarkGrey), ui.NewStyle(console.ColorDarkGrey),
getMiddlePoint(m.Block.Rectangle, optionsText, -1), util.GetMiddlePoint(m.Block.Rectangle, optionsText, -1),
) )
return return
} }
m.printAllDirectionsArrowSign(buffer, -2) m.printAllDirectionsArrowSign(buffer, -2)
arrowsTextPoint := getMiddlePoint(m.Block.Rectangle, arrowsText, 2) arrowsTextPoint := util.GetMiddlePoint(m.Block.Rectangle, arrowsText, 2)
if arrowsTextPoint.Y+1 < m.Inner.Max.Y { if arrowsTextPoint.Y+1 < m.Inner.Max.Y {
buffer.SetString( buffer.SetString(
arrowsText, arrowsText,
@ -146,16 +147,16 @@ func (m *Menu) renderHighlight(buffer *ui.Buffer) {
) )
} }
optionsTextPoint := getMiddlePoint(m.Block.Rectangle, optionsText, 3) optionsTextPoint := util.GetMiddlePoint(m.Block.Rectangle, optionsText, 3)
if optionsTextPoint.Y+1 < m.Inner.Max.Y { if optionsTextPoint.Y+1 < m.Inner.Max.Y {
buffer.SetString( buffer.SetString(
optionsText, optionsText,
ui.NewStyle(console.ColorDarkGrey), ui.NewStyle(console.ColorDarkGrey),
getMiddlePoint(m.Block.Rectangle, optionsText, 3), util.GetMiddlePoint(m.Block.Rectangle, optionsText, 3),
) )
} }
resumeTextPoint := getMiddlePoint(m.Block.Rectangle, resumeText, 4) resumeTextPoint := util.GetMiddlePoint(m.Block.Rectangle, resumeText, 4)
if resumeTextPoint.Y+1 < m.Inner.Max.Y { if resumeTextPoint.Y+1 < m.Inner.Max.Y {
buffer.SetString( buffer.SetString(
resumeText, resumeText,
@ -170,12 +171,12 @@ func (m *Menu) renderMoveAndResize(buffer *ui.Buffer) {
saveText := "<ENTER> to save changes" saveText := "<ENTER> to save changes"
if m.Dy() <= minimalMenuHeight { if m.Dy() <= minimalMenuHeight {
buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), getMiddlePoint(m.Block.Rectangle, saveText, -1)) buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), util.GetMiddlePoint(m.Block.Rectangle, saveText, -1))
return return
} }
m.printAllDirectionsArrowSign(buffer, -1) m.printAllDirectionsArrowSign(buffer, -1)
buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), getMiddlePoint(m.Block.Rectangle, saveText, 3)) buffer.SetString(saveText, ui.NewStyle(console.ColorDarkGrey), util.GetMiddlePoint(m.Block.Rectangle, saveText, 3))
} }
func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) { func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) {
@ -187,10 +188,10 @@ func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) {
} }
for i, a := range arrows { for i, a := range arrows {
printString( util.PrintString(
a, a,
ui.NewStyle(console.ColorOlive), ui.NewStyle(console.ColorOlive),
getMiddlePoint(m.Block.Rectangle, a, i+y), util.GetMiddlePoint(m.Block.Rectangle, a, i+y),
buffer, buffer,
) )
} }
@ -211,7 +212,7 @@ func (m *Menu) renderOptions(buffer *ui.Buffer) {
if option != MenuOptionPinpoint || m.component.Type == config.TypeRunChart { if option != MenuOptionPinpoint || m.component.Type == config.TypeRunChart {
offset += 2 offset += 2
point := getMiddlePoint(m.Block.Rectangle, string(option), offset-6) point := util.GetMiddlePoint(m.Block.Rectangle, string(option), offset-6)
buffer.SetString(string(option), style, point) buffer.SetString(string(option), style, point)
} }
} }
@ -239,15 +240,3 @@ func (m *Menu) drawInnerBorder(buffer *ui.Buffer) {
buffer.SetCell(ui.Cell{ui.BOTTOM_LEFT, m.BorderStyle}, image.Pt(m.Min.X+2, m.Max.Y-2)) buffer.SetCell(ui.Cell{ui.BOTTOM_LEFT, m.BorderStyle}, image.Pt(m.Min.X+2, m.Max.Y-2))
buffer.SetCell(ui.Cell{ui.BOTTOM_RIGHT, m.BorderStyle}, image.Pt(m.Max.X-3, m.Max.Y-2)) buffer.SetCell(ui.Cell{ui.BOTTOM_RIGHT, m.BorderStyle}, image.Pt(m.Max.X-3, m.Max.Y-2))
} }
// TODO move to utils
func getMiddlePoint(rectangle image.Rectangle, text string, offset int) image.Point {
return image.Pt(rectangle.Min.X+rectangle.Dx()/2-len(text)/2, rectangle.Max.Y-rectangle.Dy()/2+offset)
}
// TODO move to utils
func printString(s string, style ui.Style, p image.Point, buffer *ui.Buffer) {
for i, char := range s {
buffer.SetCell(ui.Cell{Rune: char, Style: style}, image.Pt(p.X+i, p.Y))
}
}

View File

@ -15,6 +15,7 @@ type TextBox struct {
alert *data.Alert alert *data.Alert
text string text string
border bool border bool
style ui.Style
} }
func NewTextBox(c config.TextBoxConfig, palette console.Palette) *TextBox { func NewTextBox(c config.TextBoxConfig, palette console.Palette) *TextBox {
@ -22,6 +23,7 @@ func NewTextBox(c config.TextBoxConfig, palette console.Palette) *TextBox {
box := TextBox{ box := TextBox{
Block: component.NewBlock(c.Title, *c.Border, palette), Block: component.NewBlock(c.Title, *c.Border, palette),
Consumer: data.NewConsumer(), Consumer: data.NewConsumer(),
style: ui.NewStyle(palette.BaseColor),
} }
go func() { go func() {
@ -54,6 +56,7 @@ func (t *TextBox) Draw(buffer *ui.Buffer) {
row = ui.TrimCells(row, t.Inner.Dx()-2) row = ui.TrimCells(row, t.Inner.Dx()-2)
for _, cx := range ui.BuildCellWithXArray(row) { for _, cx := range ui.BuildCellWithXArray(row) {
x, cell := cx.X, cx.Cell x, cell := cx.X, cx.Cell
cell.Style = t.style
buffer.SetCell(cell, image.Pt(x+1, y+1).Add(t.Inner.Min)) buffer.SetCell(cell, image.Pt(x+1, y+1).Add(t.Inner.Min))
} }
} }

View File

@ -2,6 +2,8 @@ package util
import ( import (
"bytes" "bytes"
ui "github.com/gizak/termui/v3"
"image"
"math" "math"
"strconv" "strconv"
"strings" "strings"
@ -74,3 +76,13 @@ func formatTrailingDigits(value string, scale int) string {
return value return value
} }
func GetMiddlePoint(rectangle image.Rectangle, text string, offset int) image.Point {
return image.Pt(rectangle.Min.X+rectangle.Dx()/2-len(text)/2, rectangle.Max.Y-rectangle.Dy()/2+offset)
}
func PrintString(s string, style ui.Style, p image.Point, buffer *ui.Buffer) {
for i, char := range s {
buffer.SetCell(ui.Cell{Rune: char, Style: style}, image.Pt(p.X+i, p.Y))
}
}

View File

@ -1,4 +1,4 @@
package component package util
import ( import (
"image" "image"
@ -38,3 +38,9 @@ func GetDistance(p1 image.Point, p2 image.Point) float64 {
y := math.Abs(float64(p1.Y - p2.Y)) y := math.Abs(float64(p1.Y - p2.Y))
return math.Sqrt(x*x + y*y) return math.Sqrt(x*x + y*y)
} }
func GetRectCoordinates(area image.Rectangle, width int, height int) (int, int, int, int) {
x1 := area.Min.X + area.Dx()/2 - width/2
y1 := area.Min.Y + area.Dy()/2 - height
return x1, y1, x1 + width, y1 + height + 2
}

View File

@ -21,7 +21,7 @@ type Config struct {
AsciiBoxes []AsciiBoxConfig `yaml:"asciiboxes,omitempty"` AsciiBoxes []AsciiBoxConfig `yaml:"asciiboxes,omitempty"`
} }
func Load() (Config, Options) { func LoadConfig() (Config, Options) {
var opt Options var opt Options
_, err := flags.Parse(&opt) _, err := flags.Parse(&opt)
@ -114,7 +114,7 @@ func saveFile(config *Config, fileName string) {
log.Fatalf("Can't marshal config file: %v", err) log.Fatalf("Can't marshal config file: %v", err)
} }
err = ioutil.WriteFile(fileName, file, 0644) err = ioutil.WriteFile(fileName, file, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("Can't save config file: %v", err) log.Fatalf("Can't save config file: %v", err)
} }

View File

@ -14,7 +14,7 @@ import (
"time" "time"
) )
const interactiveShellStartupTimeout = time.Second const interactiveShellStartupTimeout = 100 * time.Millisecond
type Item struct { type Item struct {
Label string Label string

View File

@ -29,7 +29,7 @@ func NewSampler(consumer *Consumer, items []*Item, triggers []*Trigger, options
go func() { go func() {
for ; true; <-ticker.C { for ; true; <-ticker.C {
for _, item := range sampler.items { for _, item := range sampler.items {
go sampler.sample(item, options) sampler.sample(item, options)
} }
} }
}() }()
@ -39,7 +39,7 @@ func NewSampler(consumer *Consumer, items []*Item, triggers []*Trigger, options
select { select {
case sample := <-sampler.triggersChannel: case sample := <-sampler.triggersChannel:
for _, t := range sampler.triggers { for _, t := range sampler.triggers {
go t.Execute(sample) t.Execute(sample)
} }
} }
} }

19
main.go
View File

@ -15,6 +15,7 @@ import (
"github.com/sqshq/sampler/console" "github.com/sqshq/sampler/console"
"github.com/sqshq/sampler/data" "github.com/sqshq/sampler/data"
"github.com/sqshq/sampler/event" "github.com/sqshq/sampler/event"
"github.com/sqshq/sampler/storage"
"time" "time"
) )
@ -31,12 +32,12 @@ func (s *Starter) start(drawable ui.Drawable, consumer *data.Consumer, component
items := data.NewItems(itemsConfig, *componentConfig.RateMs) items := data.NewItems(itemsConfig, *componentConfig.RateMs)
data.NewSampler(consumer, items, triggers, s.opt, s.cfg.Variables, *componentConfig.RateMs) data.NewSampler(consumer, items, triggers, s.opt, s.cfg.Variables, *componentConfig.RateMs)
s.lout.AddComponent(cpt) s.lout.AddComponent(cpt)
time.Sleep(100 * time.Millisecond) // desync coroutines time.Sleep(10 * time.Millisecond) // desync coroutines
} }
func main() { func main() {
cfg, opt := config.Load() cfg, opt := config.LoadConfig()
console.Init() console.Init()
defer console.Close() defer console.Close()
@ -47,10 +48,11 @@ func main() {
palette := console.GetPalette(*cfg.Theme) palette := console.GetPalette(*cfg.Theme)
width, height := ui.TerminalDimensions() width, height := ui.TerminalDimensions()
lout := layout.NewLayout(width, height, component.NewStatusLine(opt.ConfigFile, palette), component.NewMenu(palette)) lout := layout.NewLayout(width, height, component.NewStatusLine(opt.ConfigFile, palette), component.NewMenu(palette), component.NewIntro(palette))
starter := &Starter{lout, player, opt, cfg} starter := &Starter{lout, player, opt, cfg}
license := storage.GetLicense()
for _, c := range cfg.RunCharts { for _, c := range cfg.RunCharts {
cpt := runchart.NewRunChart(c, palette) cpt := runchart.NewRunChart(c, palette)
starter.start(cpt, cpt.Consumer, c.ComponentConfig, c.Items, c.Triggers) starter.start(cpt, cpt.Consumer, c.ComponentConfig, c.Items, c.Triggers)
@ -81,6 +83,15 @@ func main() {
starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Item}, c.Triggers) starter.start(cpt, cpt.Consumer, c.ComponentConfig, []config.Item{c.Item}, c.Triggers)
} }
if license == nil {
lout.RunIntro()
storage.InitLicense()
} else if !license.Purchased /* && random */ {
// TODO lout.showNagWindow() with timeout and OK button
// TODO verify license
// TODO send stats
}
handler := event.NewHandler(lout, opt) handler := event.NewHandler(lout, opt)
handler.HandleEvents() handler.HandleEvents()
} }

53
storage/license.go Normal file
View File

@ -0,0 +1,53 @@
package storage
import (
"gopkg.in/yaml.v2"
"log"
)
type License struct {
Purchased bool
Valid bool
Key *string
Username *string
Company *string
}
const licenseFileName = "license.yml"
func GetLicense() *License {
if !fileExists(licenseFileName) {
return nil
} else {
file := readStorageFile(getPlatformStoragePath(licenseFileName))
license := new(License)
err := yaml.Unmarshal(file, license)
if err != nil {
log.Fatalf("Can't read license file: %v", err)
}
return license
}
}
func InitLicense() {
license := License{
Purchased: false,
Valid: false,
}
file, err := yaml.Marshal(license)
if err != nil {
log.Fatalf("Can't marshal config file: %v", err)
}
initStorage()
saveStorageFile(file, getPlatformStoragePath(licenseFileName))
}
func SaveLicense() {
// TODO
}

6
storage/stats.go Normal file
View File

@ -0,0 +1,6 @@
package storage
// TODO
// version
// launch count
// components count by type

56
storage/storage.go Normal file
View File

@ -0,0 +1,56 @@
package storage
import (
"io/ioutil"
"log"
"os"
"path/filepath"
"runtime"
)
const (
macOSDir = "/Library/Application Support/Sampler"
linuxDir = "/.config/Sampler"
windowsDir = "%LOCALAPPDATA%\\Sampler"
)
func fileExists(filename string) bool {
_, err := os.Stat(getPlatformStoragePath(filename))
return !os.IsNotExist(err)
}
func getPlatformStoragePath(filename string) string {
home, _ := os.UserHomeDir()
switch runtime.GOOS {
case "darwin":
return filepath.Join(home, macOSDir, filename)
case "windows":
return filepath.Join(home, windowsDir, filename)
default:
return filepath.Join(linuxDir, filename)
}
}
func initStorage() {
err := os.MkdirAll(getPlatformStoragePath(""), os.ModePerm)
if err != nil {
log.Fatalf("Failed to init storage: %v", err)
}
}
func readStorageFile(path string) []byte {
file, err := ioutil.ReadFile(path)
if err != nil {
log.Fatalf("Failed to the read storage file: %s", path)
}
return file
}
func saveStorageFile(file []byte, fileName string) {
err := ioutil.WriteFile(fileName, file, os.ModePerm)
if err != nil {
log.Fatalf("Failed to save the storage file: %v", err)
}
}