add intro page and storage initialization
This commit is contained in:
parent
8fa382e37d
commit
911be1ba00
|
@ -0,0 +1,8 @@
|
|||
package client
|
||||
|
||||
import "github.com/sqshq/sampler/storage"
|
||||
|
||||
// TODO
|
||||
func loadLicense(key string) *storage.License {
|
||||
return nil
|
||||
}
|
|
@ -44,7 +44,7 @@ func RenderAlert(alert *data.Alert, area image.Rectangle, buffer *ui.Buffer) {
|
|||
}
|
||||
|
||||
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.Draw(buffer)
|
||||
|
||||
|
@ -52,13 +52,6 @@ func RenderAlert(alert *data.Alert, area image.Rectangle, buffer *ui.Buffer) {
|
|||
|
||||
for i := 0; i < len(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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
ui "github.com/gizak/termui/v3"
|
||||
"github.com/sqshq/sampler/component"
|
||||
"github.com/sqshq/sampler/component/runchart"
|
||||
"github.com/sqshq/sampler/component/util"
|
||||
"github.com/sqshq/sampler/config"
|
||||
"github.com/sqshq/sampler/console"
|
||||
"github.com/sqshq/sampler/data"
|
||||
|
@ -16,6 +17,7 @@ type Layout struct {
|
|||
Components []*component.Component
|
||||
statusbar *component.StatusBar
|
||||
menu *component.Menu
|
||||
intro *component.Intro
|
||||
ChangeModeEvents chan Mode
|
||||
mode Mode
|
||||
selection int
|
||||
|
@ -25,12 +27,13 @@ type Mode rune
|
|||
|
||||
const (
|
||||
ModeDefault Mode = 0
|
||||
ModePause Mode = 1
|
||||
ModeComponentSelect Mode = 2
|
||||
ModeMenuOptionSelect Mode = 3
|
||||
ModeComponentMove Mode = 4
|
||||
ModeComponentResize Mode = 5
|
||||
ModeChartPinpoint Mode = 6
|
||||
ModeIntro Mode = 1
|
||||
ModePause Mode = 2
|
||||
ModeComponentSelect Mode = 3
|
||||
ModeMenuOptionSelect Mode = 4
|
||||
ModeComponentMove Mode = 5
|
||||
ModeComponentResize Mode = 6
|
||||
ModeChartPinpoint Mode = 7
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -38,10 +41,11 @@ const (
|
|||
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.SetRect(0, 0, width, height)
|
||||
intro.SetRect(0, 0, width, height)
|
||||
statusline.SetRect(0, height-statusbarHeight, width, height)
|
||||
|
||||
return &Layout{
|
||||
|
@ -49,6 +53,7 @@ func NewLayout(width, height int, statusline *component.StatusBar, menu *compone
|
|||
Components: make([]*component.Component, 0),
|
||||
statusbar: statusline,
|
||||
menu: menu,
|
||||
intro: intro,
|
||||
mode: ModeDefault,
|
||||
selection: 0,
|
||||
ChangeModeEvents: make(chan Mode, 10),
|
||||
|
@ -59,12 +64,19 @@ func (l *Layout) AddComponent(cpt *component.Component) {
|
|||
l.Components = append(l.Components, cpt)
|
||||
}
|
||||
|
||||
func (l *Layout) RunIntro() {
|
||||
l.mode = ModeIntro
|
||||
}
|
||||
|
||||
func (l *Layout) changeMode(m Mode) {
|
||||
l.mode = m
|
||||
l.ChangeModeEvents <- m
|
||||
}
|
||||
|
||||
func (l *Layout) HandleMouseClick(x int, y int) {
|
||||
if l.mode == ModeIntro {
|
||||
return
|
||||
}
|
||||
l.menu.Idle()
|
||||
selected, i := l.findComponentAtPoint(image.Point{X: x, Y: y})
|
||||
if selected == nil {
|
||||
|
@ -118,6 +130,14 @@ func (l *Layout) HandleKeyboardEvent(e string) {
|
|||
case ModeComponentResize:
|
||||
l.menu.Idle()
|
||||
l.changeMode(ModeDefault)
|
||||
break
|
||||
case ModeIntro:
|
||||
page := l.intro.GetSelectedPage()
|
||||
if page == component.IntroPageWelcome {
|
||||
l.intro.NextPage()
|
||||
} else {
|
||||
l.changeMode(ModeDefault)
|
||||
}
|
||||
}
|
||||
case console.KeyEsc:
|
||||
l.resetAlerts()
|
||||
|
@ -180,6 +200,8 @@ func (l *Layout) HandleKeyboardEvent(e string) {
|
|||
selected.Move(0, -1)
|
||||
case ModeComponentResize:
|
||||
selected.Resize(0, -1)
|
||||
case ModeIntro:
|
||||
l.intro.Up()
|
||||
}
|
||||
case console.KeyDown:
|
||||
switch l.mode {
|
||||
|
@ -195,6 +217,8 @@ func (l *Layout) HandleKeyboardEvent(e string) {
|
|||
selected.Move(0, 1)
|
||||
case ModeComponentResize:
|
||||
selected.Resize(0, 1)
|
||||
case ModeIntro:
|
||||
l.intro.Down()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -232,21 +256,21 @@ func (l *Layout) moveSelection(direction string) {
|
|||
|
||||
switch direction {
|
||||
case console.KeyLeft:
|
||||
previouslySelectedCornerPoint = component.GetRectLeftSideCenter(previouslySelected.GetRect())
|
||||
newlySelectedCornerPoint = component.GetRectRightSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||
currentCornerPoint = component.GetRectRightSideCenter(current.GetRect())
|
||||
previouslySelectedCornerPoint = util.GetRectLeftSideCenter(previouslySelected.GetRect())
|
||||
newlySelectedCornerPoint = util.GetRectRightSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||
currentCornerPoint = util.GetRectRightSideCenter(current.GetRect())
|
||||
case console.KeyRight:
|
||||
previouslySelectedCornerPoint = component.GetRectRightSideCenter(previouslySelected.GetRect())
|
||||
newlySelectedCornerPoint = component.GetRectLeftSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||
currentCornerPoint = component.GetRectLeftSideCenter(current.GetRect())
|
||||
previouslySelectedCornerPoint = util.GetRectRightSideCenter(previouslySelected.GetRect())
|
||||
newlySelectedCornerPoint = util.GetRectLeftSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||
currentCornerPoint = util.GetRectLeftSideCenter(current.GetRect())
|
||||
case console.KeyUp:
|
||||
previouslySelectedCornerPoint = component.GetRectTopSideCenter(previouslySelected.GetRect())
|
||||
newlySelectedCornerPoint = component.GetRectBottomSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||
currentCornerPoint = component.GetRectBottomSideCenter(current.GetRect())
|
||||
previouslySelectedCornerPoint = util.GetRectTopSideCenter(previouslySelected.GetRect())
|
||||
newlySelectedCornerPoint = util.GetRectBottomSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||
currentCornerPoint = util.GetRectBottomSideCenter(current.GetRect())
|
||||
case console.KeyDown:
|
||||
previouslySelectedCornerPoint = component.GetRectBottomSideCenter(previouslySelected.GetRect())
|
||||
newlySelectedCornerPoint = component.GetRectTopSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||
currentCornerPoint = component.GetRectTopSideCenter(current.GetRect())
|
||||
previouslySelectedCornerPoint = util.GetRectBottomSideCenter(previouslySelected.GetRect())
|
||||
newlySelectedCornerPoint = util.GetRectTopSideCenter(l.getComponent(newlySelectedIndex).GetRect())
|
||||
currentCornerPoint = util.GetRectTopSideCenter(current.GetRect())
|
||||
}
|
||||
|
||||
switch direction {
|
||||
|
@ -279,6 +303,12 @@ func (l *Layout) Draw(buffer *ui.Buffer) {
|
|||
columnWidth := float64(l.GetRect().Dx()) / float64(console.ColumnsCount)
|
||||
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 {
|
||||
rectangle := calculateComponentCoordinates(c, columnWidth, rowHeight)
|
||||
c.SetRect(rectangle.Min.X, rectangle.Min.Y, rectangle.Max.X, rectangle.Max.Y)
|
||||
|
|
|
@ -2,6 +2,7 @@ package component
|
|||
|
||||
import (
|
||||
ui "github.com/gizak/termui/v3"
|
||||
"github.com/sqshq/sampler/component/util"
|
||||
"github.com/sqshq/sampler/config"
|
||||
"github.com/sqshq/sampler/console"
|
||||
"image"
|
||||
|
@ -130,14 +131,14 @@ func (m *Menu) renderHighlight(buffer *ui.Buffer) {
|
|||
buffer.SetString(
|
||||
optionsText,
|
||||
ui.NewStyle(console.ColorDarkGrey),
|
||||
getMiddlePoint(m.Block.Rectangle, optionsText, -1),
|
||||
util.GetMiddlePoint(m.Block.Rectangle, optionsText, -1),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
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 {
|
||||
buffer.SetString(
|
||||
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 {
|
||||
buffer.SetString(
|
||||
optionsText,
|
||||
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 {
|
||||
buffer.SetString(
|
||||
resumeText,
|
||||
|
@ -170,12 +171,12 @@ func (m *Menu) renderMoveAndResize(buffer *ui.Buffer) {
|
|||
saveText := "<ENTER> to save changes"
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -187,10 +188,10 @@ func (m *Menu) printAllDirectionsArrowSign(buffer *ui.Buffer, y int) {
|
|||
}
|
||||
|
||||
for i, a := range arrows {
|
||||
printString(
|
||||
util.PrintString(
|
||||
a,
|
||||
ui.NewStyle(console.ColorOlive),
|
||||
getMiddlePoint(m.Block.Rectangle, a, i+y),
|
||||
util.GetMiddlePoint(m.Block.Rectangle, a, i+y),
|
||||
buffer,
|
||||
)
|
||||
}
|
||||
|
@ -211,7 +212,7 @@ func (m *Menu) renderOptions(buffer *ui.Buffer) {
|
|||
|
||||
if option != MenuOptionPinpoint || m.component.Type == config.TypeRunChart {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -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_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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ type TextBox struct {
|
|||
alert *data.Alert
|
||||
text string
|
||||
border bool
|
||||
style ui.Style
|
||||
}
|
||||
|
||||
func NewTextBox(c config.TextBoxConfig, palette console.Palette) *TextBox {
|
||||
|
@ -22,6 +23,7 @@ func NewTextBox(c config.TextBoxConfig, palette console.Palette) *TextBox {
|
|||
box := TextBox{
|
||||
Block: component.NewBlock(c.Title, *c.Border, palette),
|
||||
Consumer: data.NewConsumer(),
|
||||
style: ui.NewStyle(palette.BaseColor),
|
||||
}
|
||||
|
||||
go func() {
|
||||
|
@ -54,6 +56,7 @@ func (t *TextBox) Draw(buffer *ui.Buffer) {
|
|||
row = ui.TrimCells(row, t.Inner.Dx()-2)
|
||||
for _, cx := range ui.BuildCellWithXArray(row) {
|
||||
x, cell := cx.X, cx.Cell
|
||||
cell.Style = t.style
|
||||
buffer.SetCell(cell, image.Pt(x+1, y+1).Add(t.Inner.Min))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package util
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
ui "github.com/gizak/termui/v3"
|
||||
"image"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -74,3 +76,13 @@ func formatTrailingDigits(value string, scale int) string {
|
|||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package component
|
||||
package util
|
||||
|
||||
import (
|
||||
"image"
|
||||
|
@ -38,3 +38,9 @@ func GetDistance(p1 image.Point, p2 image.Point) float64 {
|
|||
y := math.Abs(float64(p1.Y - p2.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
|
||||
}
|
|
@ -21,7 +21,7 @@ type Config struct {
|
|||
AsciiBoxes []AsciiBoxConfig `yaml:"asciiboxes,omitempty"`
|
||||
}
|
||||
|
||||
func Load() (Config, Options) {
|
||||
func LoadConfig() (Config, Options) {
|
||||
|
||||
var opt Options
|
||||
_, err := flags.Parse(&opt)
|
||||
|
@ -114,7 +114,7 @@ func saveFile(config *Config, fileName string) {
|
|||
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 {
|
||||
log.Fatalf("Can't save config file: %v", err)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const interactiveShellStartupTimeout = time.Second
|
||||
const interactiveShellStartupTimeout = 100 * time.Millisecond
|
||||
|
||||
type Item struct {
|
||||
Label string
|
||||
|
|
|
@ -29,7 +29,7 @@ func NewSampler(consumer *Consumer, items []*Item, triggers []*Trigger, options
|
|||
go func() {
|
||||
for ; true; <-ticker.C {
|
||||
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 {
|
||||
case sample := <-sampler.triggersChannel:
|
||||
for _, t := range sampler.triggers {
|
||||
go t.Execute(sample)
|
||||
t.Execute(sample)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
19
main.go
19
main.go
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/sqshq/sampler/console"
|
||||
"github.com/sqshq/sampler/data"
|
||||
"github.com/sqshq/sampler/event"
|
||||
"github.com/sqshq/sampler/storage"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -31,12 +32,12 @@ func (s *Starter) start(drawable ui.Drawable, consumer *data.Consumer, component
|
|||
items := data.NewItems(itemsConfig, *componentConfig.RateMs)
|
||||
data.NewSampler(consumer, items, triggers, s.opt, s.cfg.Variables, *componentConfig.RateMs)
|
||||
s.lout.AddComponent(cpt)
|
||||
time.Sleep(100 * time.Millisecond) // desync coroutines
|
||||
time.Sleep(10 * time.Millisecond) // desync coroutines
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
cfg, opt := config.Load()
|
||||
cfg, opt := config.LoadConfig()
|
||||
|
||||
console.Init()
|
||||
defer console.Close()
|
||||
|
@ -47,10 +48,11 @@ func main() {
|
|||
palette := console.GetPalette(*cfg.Theme)
|
||||
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}
|
||||
|
||||
license := storage.GetLicense()
|
||||
|
||||
for _, c := range cfg.RunCharts {
|
||||
cpt := runchart.NewRunChart(c, palette)
|
||||
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)
|
||||
}
|
||||
|
||||
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.HandleEvents()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package storage
|
||||
|
||||
// TODO
|
||||
// version
|
||||
// launch count
|
||||
// components count by type
|
|
@ -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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue