Skip to content

Commit

Permalink
feat: switch between timer and spinner models
Browse files Browse the repository at this point in the history
  • Loading branch information
bashbunni committed Aug 9, 2022
1 parent 41da988 commit ec0f4a4
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 97 deletions.
9 changes: 0 additions & 9 deletions docs/creating-nested-models.md

This file was deleted.

116 changes: 28 additions & 88 deletions examples/nested-models/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"log"
"time"

"github.com/charmbracelet/bubbles/spinner"
"github.com/charmbracelet/bubbles/timer"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
Expand All @@ -15,123 +13,65 @@ type sessionState uint

const (
defaultTime = time.Minute
timerView sessionState = iota
spinnerView
timerModel sessionState = iota
spinnerModel
)

var (
// Available spinners
spinners = []spinner.Spinner{
spinner.Line,
spinner.Dot,
spinner.MiniDot,
spinner.Jump,
spinner.Pulse,
spinner.Points,
spinner.Globe,
spinner.Moon,
spinner.Monkey,
}
spinnerStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("69"))
helpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241")).Render
helpStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("241")).Render
current = timerModel
models []tea.Model
)

type mainModel struct {
state sessionState
timer timer.Model
spinner spinner.Model
index int
}
type MainModel struct{}

// New: Create a new main model
func New(timeout time.Duration) mainModel {
func New(timeout time.Duration) MainModel {
// initialize your model; timerView is the first "view" we want to see
m := mainModel{state: timerView}
m.timer = timer.New(timeout)
m.spinner = spinner.New()
models = []tea.Model{}
models = append(models, NewTimer(timeout))
models = append(models, NewSpinner())
m := MainModel{}
return m
}

func (m mainModel) Init() tea.Cmd {
func (m MainModel) Init() tea.Cmd {
// start the timer and spinner on program start
return tea.Batch(m.timer.Init(), m.spinner.Tick)
return tea.Batch(models[current].Init())
}

func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
var cmds []tea.Cmd
func (m MainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
// Handle IO -> keypress, WindowSizeMSg
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
return m, tea.Quit
case "enter":
if m.state == timerView {
m.state = spinnerView
} else {
m.state = timerView
}
case "n":
if m.state == timerView {
m.timer = timer.New(defaultTime)
cmds = append(cmds, m.timer.Init())
} else {
m.Next()
m.resetSpinner()
cmds = append(cmds, spinner.Tick)
}
}
switch m.state {
// update whichever model is focused
case spinnerView:
m.spinner, cmd = m.spinner.Update(msg)
cmds = append(cmds, cmd)
default:
// another way to do it
newModel, cmd := m.timer.Update(msg)
m.timer = newModel
// if this were your own model, you would need to wrap the type
// before assignment because its type would be tea.Model
// i.e. m.list = newModel.(list.Model)
cmds = append(cmds, cmd)
}
case spinner.TickMsg:
var cmd tea.Cmd
m.spinner, cmd = m.spinner.Update(msg)
cmds = append(cmds, cmd)
case timer.TickMsg:
var cmd tea.Cmd
m.timer, cmd = m.timer.Update(msg)
cmds = append(cmds, cmd)
}
return m, tea.Batch(cmds...)
return models[current].Update(msg)
}

func (m mainModel) View() string {
func (m MainModel) View() string {
var s string
switch m.state {
case spinnerView:
s += m.spinner.View() + "\n"
default:
s += m.timer.View() + "\n"
}
s += helpStyle("enter: change view • n: new spinner/timer • q: exit\n")
s += models[current].View() + "\n"
s += helpStyle("right: next - left: prev - enter: new spinner")
return s
}

func (m *mainModel) Next() {
if m.index == len(spinners)-1 {
m.index = 0
func NextModel() {
if int(current) == len(models)-1 {
current = 0
} else {
m.index++
current++
}
}

func (m *mainModel) resetSpinner() {
m.spinner = spinner.New()
m.spinner.Style = spinnerStyle
m.spinner.Spinner = spinners[m.index]
func PrevModel() {
if int(current) == 0 {
current = sessionState(len(models) - 1)
} else {
current--
}
}

func main() {
Expand Down
83 changes: 83 additions & 0 deletions examples/nested-models/spinners.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package main

import (
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)

var (
spinners = []spinner.Spinner{
spinner.Line,
spinner.Dot,
spinner.MiniDot,
spinner.Jump,
spinner.Pulse,
spinner.Points,
spinner.Globe,
spinner.Moon,
spinner.Monkey,
}
spinnerStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("69"))
)

type Spinner struct {
spinner spinner.Model
index int
}

func NewSpinner() *Spinner {
return &Spinner{spinner: spinner.New()}
}

func (m Spinner) Init() tea.Cmd {
return nil
}

func (m Spinner) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
return m, tea.Quit
case "enter":
m.Next()
m.resetSpinner()
case "right", "l":
NextModel()
return models[current].Update(nil)
case "left", "h":
PrevModel()
return models[current].Update(nil)
}
}
m.spinner, cmd = m.spinner.Update(msg)
return m, cmd
}

func (m Spinner) View() string {
return spinnerStyle.Render(m.spinner.View())
}

func (m *Spinner) resetSpinner() {
m.spinner = spinner.New()
m.spinner.Style = spinnerStyle
m.spinner.Spinner = spinners[m.index]
}

func (m *Spinner) Next() {
if m.index == len(spinners)-1 {
m.index = 0
} else {
m.index++
}
}

func (m *Spinner) Prev() {
if m.index == 0 {
m.index = len(spinners) - 1
} else {
m.index--
}
}
43 changes: 43 additions & 0 deletions examples/nested-models/timer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"time"

"github.com/charmbracelet/bubbles/timer"
tea "github.com/charmbracelet/bubbletea"
)

type Timer struct {
timer timer.Model
}

func NewTimer(timeout time.Duration) *Timer {
return &Timer{timer: timer.New(timeout)}
}

func (m Timer) Init() tea.Cmd {
return m.timer.Init()
}

func (m Timer) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
return m, tea.Quit
case "right", "l":
NextModel()
return models[current].Update(nil)
case "left", "h":
PrevModel()
return models[current].Update(nil)
}
}
m.timer, cmd = m.timer.Update(msg)
return m, cmd
}

func (m Timer) View() string {
return m.timer.View()
}

0 comments on commit ec0f4a4

Please sign in to comment.