clone

fifteen puzzle games for the terminal, with daily puzzles, weekly ladders and xp, built on bubble tea

bug/architecture-test-trim-path
puzzletea / app / update.go
update.go 4.3K
1package app23import (4 "github.com/FelineStateMachine/puzzletea/game"5 "github.com/FelineStateMachine/puzzletea/store"67 "charm.land/bubbles/v2/key"8 tea "charm.land/bubbletea/v2"9)1011func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {12 switch msg := msg.(type) {13 case spawnCompleteMsg:14 next, cmd := m.handleSpawnComplete(msg.jobID, msg.result)15 return next, cmd16 case game.SpawnCompleteMsg:17 next, cmd := m.handleSpawnComplete(m.session.spawnJobID, msg)18 return next, cmd19 case exportCompleteMsg:20 next, cmd := m.handleExportComplete(msg)21 return next, cmd22 case exportSubmitAction:23 next, cmd := m.handleExportSubmit()24 return next, cmd25 case backAction:26 return msg.applyToModel(m)27 case tea.WindowSizeMsg:28 m = m.handleWindowSize(msg)29 if m.state != gameView {30 return m, nil31 }32 }3334 next, cmd, handled := m.handleGlobalKey(msg)35 if handled {36 return next, cmd37 }38 m = next3940 if m.state == gameView {41 gameCmd := newSessionController(&m).updateActiveGame(msg)42 return m, gameCmd43 }4445 screen := m.activeScreen()46 if screen == nil {47 return m, nil48 }4950 // Clear stale notices when the user interacts with the export form.51 if m.state == exportView {52 switch msg.(type) {53 case tea.KeyPressMsg, tea.MouseClickMsg:54 m = m.clearNotice()55 }56 }5758 nextScreen, screenCmd, action := screen.Update(msg)59 if m.screens == nil {60 m.screens = make(map[viewState]screenModel)61 }62 m.screens[m.state] = nextScreen63 if action == nil {64 return m, screenCmd65 }6667 next, actionCmd := m.handleScreenAction(action)68 return next, tea.Batch(screenCmd, actionCmd)69}7071func (m model) resizeActiveScreen() model {72 screen := m.screens[m.state] // nil map read is safe; returns nil73 if screen == nil {74 return m75 }76 m.screens[m.state] = screen.Resize(m.width, m.height)77 return m78}7980func (m model) handleWindowSize(msg tea.WindowSizeMsg) model {81 m.width = msg.Width82 m.height = msg.Height83 if m.state == gameView {84 return m85 }86 return m.resizeActiveScreen()87}8889func (m model) handleGlobalKey(msg tea.Msg) (model, tea.Cmd, bool) {90 keyMsg, ok := msg.(tea.KeyPressMsg)91 if !ok {92 return m, nil, false93 }9495 if m.state == generatingView {96 switch {97 case key.Matches(keyMsg, rootKeys.Escape):98 returnState := m.activeSpawnReturnState()99 m.cancelActiveSpawn()100 m.state = returnState101 return m.resizeActiveScreen(), nil, true102 case key.Matches(keyMsg, rootKeys.Quit):103 return m, tea.Quit, true104 }105 return m, nil, true106 }107108 if m.state == exportRunningView {109 switch {110 case key.Matches(keyMsg, rootKeys.Escape):111 m.cancelActiveExport()112 m.state = exportView113 return m.resizeActiveScreen(), nil, true114 case key.Matches(keyMsg, rootKeys.Quit):115 return m, tea.Quit, true116 }117 return m, nil, true118 }119120 if m.state == gameView {121 switch {122 case key.Matches(keyMsg, rootKeys.Enter):123 next, cmd, handled := m.advanceSolvedWeekly()124 if handled {125 return next, cmd, true126 }127 case key.Matches(keyMsg, rootKeys.Escape):128 returnState := m.session.returnState129 m = saveCurrentGame(m, store.StatusInProgress)130 m.state = returnState131 if returnState == weeklyView {132 m = m.refreshWeeklyBrowser()133 m = m.initScreen(weeklyView)134 }135 m.debug.enabled = false136 return m, nil, true137 case key.Matches(keyMsg, rootKeys.Quit):138 m = saveCurrentGame(m, store.StatusAbandoned)139 return m, tea.Quit, true140 case key.Matches(keyMsg, rootKeys.Debug):141 m.debug.enabled = !m.debug.enabled142 return m, nil, true143 case key.Matches(keyMsg, rootKeys.FullHelp):144 m.help.showFull = !m.help.showFull145 if m.session.game != nil {146 m.session.game, _ = m.session.game.Update(game.HelpToggleMsg{Show: m.help.showFull})147 }148 return m, nil, true149 case key.Matches(keyMsg, rootKeys.ResetGame):150 if m.session.game != nil {151 m.session.game = m.session.game.Reset()152 }153 return m, nil, true154 }155 return m, nil, false156 }157158 switch {159 case key.Matches(keyMsg, rootKeys.Quit):160 return m, tea.Quit, true161 case key.Matches(keyMsg, rootKeys.Debug):162 m.debug.enabled = !m.debug.enabled163 return m, nil, true164 case key.Matches(keyMsg, rootKeys.FullHelp):165 m.help.showFull = !m.help.showFull166 return m, nil, true167 default:168 return m, nil, false169 }170}171172func (m model) activeSpawnReturnState() viewState {173 if m.session.spawn == nil {174 return modeSelectView175 }176 return m.session.spawn.returnState177}178179func (m model) handleScreenAction(action screenAction) (model, tea.Cmd) {180 return action.applyToModel(m)181}