Closed adrien-barret closed 3 years ago
I think you don't need multiple models, just have two separate structs/maps/slices/whatever for the respective selection state (checked items, current item) and a separate field that holds which of the two lists is active, both in the same model. From this, you can render the two lists consecutively (or, if that's what you're after, both at once with the current item moving between lists).
by chance do you get time to make a small example ? I tried that but it seems the view don't load and the keyboard movements get some issues as it go with two slices
Here you go… This example shows both lists at once, does without any fancy colors and such, and can be quit via Esc or Ctrl-C. Items can be toggled via Space or Enter. As it is, it lacks a means of submitting the selection, does not validate your constraints (selecting two flavors), and can surely be improved/optimized, but you should get the idea.
package main
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
)
func main() {
m := &model{
flavors: []item{
{"orange", false},
{"strawberry", false},
{"watermelon", false},
{"apple", false},
},
adds: []item{
{"candies", false},
{"mixed colors", false},
{"strange glass shape", false},
},
}
if err := tea.NewProgram(m).Start(); err != nil {
panic(fmt.Sprintf("failed to run program: %v", err))
}
}
type model struct {
flavors, adds []item
list, item int
}
type item struct {
text string
checked bool
}
func (m *model) Init() tea.Cmd {
return nil
}
func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch typed := msg.(type) {
case tea.KeyMsg:
return m, m.handleKeyMsg(typed)
}
return m, nil
}
func (m *model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
switch msg.String() {
case "esc", "ctrl+c":
return tea.Quit
case " ", "enter":
switch m.list {
case 0:
m.flavors[m.item].checked = !m.flavors[m.item].checked
case 1:
m.adds[m.item].checked = !m.adds[m.item].checked
}
case "up":
if m.item > 0 {
m.item--
} else if m.list > 0 {
m.list--
m.item = len(m.flavors) - 1
}
case "down":
switch m.list {
case 0:
if m.item+1 < len(m.flavors) {
m.item++
} else {
m.list++
m.item = 0
}
case 1:
if m.item+1 < len(m.adds) {
m.item++
}
}
}
return nil
}
func (m *model) View() string {
curFlavor, curAdd := -1, -1
switch m.list {
case 0:
curFlavor = m.item
case 1:
curAdd = m.item
}
return m.renderList("choose two flavors", m.flavors, curFlavor) +
"\n" +
m.renderList("select adds", m.adds, curAdd)
}
func (m *model) renderList(header string, items []item, selected int) string {
out := "~ " + header + ":\n"
for i, item := range items {
sel := " "
if i == selected {
sel = ">"
}
check := " "
if items[i].checked {
check = "✓"
}
out += fmt.Sprintf("%s [%s] %s\n", sel, check, item.text)
}
return out
}
thanks ! :)
Hi,
I'm looking in the doc but don't fully understand how to create multiple model and view in the same file. like: create your own drink:
~ choose two flavors: [] orange [] strawberrie [] watermelon [] apple
~ select adds: [] candies [] mixed colors [] strange glass shape