- commit
- 5845928737dc6f8dd7072324272a8666b05173e7
- parent
- 60ec793a610730b275625a9c7ca7c3515067d903
- author
- Dami <dami.etoile@gmail.com>
| M | app/ | 19 | +------- |
| M | app/ | 1 | + |
| M | app/ | 1 | + |
| M | app/ | 1 | + |
| M | app/ | 1 | + |
| M | app/ | 12 | ++++- |
| M | app/ | 69 | ++++++++++++++++++++++++------ |
| M | app/ | 24 | ---------- |
| M | app/ | 42 | ------------------ |
| M | app/ | 40 | ----------------- |
| M | app/ | 1 | + |
| M | app/ | 2 | + |
| M | app/ | 11 | +++- |
| M | app/ | 24 | +++++++--- |
| R | app/ | 0 | |
| M | app/ | 1 | + |
| M | app/ | 2 | + |
@@ -201,8 +201,6 @@ type exportScreen struct {
201201 export exportModel202202 }203203 204-func (s exportScreen) State() viewState { return exportView }205-206204 func (s exportScreen) Resize(width, height int) screenModel {207205 s.width = width208206 s.height = height@@ -232,20 +230,12 @@ func (s exportScreen) View(notice noticeState) string {
232230 )233231 }234232 235-func (s exportScreen) Apply(m model) model {236- m.state = exportView237- m.export = s.export238- return m239-}240-241233 type exportRunningScreen struct {242234 width int243235 height int244236 spinner spinner.Model245237 }246238 247-func (s exportRunningScreen) State() viewState { return exportRunningView }248-249239 func (s exportRunningScreen) Resize(width, height int) screenModel {250240 s.width = width251241 s.height = height@@ -264,12 +254,6 @@ func (s exportRunningScreen) View(notice noticeState) string {
264254 return ui.CenterView(s.width, s.height, box)265255 }266256 267-func (s exportRunningScreen) Apply(m model) model {268- m.state = exportRunningView269- m.spinner = s.spinner270- return m271-}272-273257 func (m model) handleExportEnter() (tea.Model, tea.Cmd) {274258 if !m.export.initialized {275259 spec := m.initialExportSpec()@@ -279,7 +263,7 @@ func (m model) handleExportEnter() (tea.Model, tea.Cmd) {
279263 }280264 m.state = exportView281265 m = m.clearNotice()282- return m.resizeActiveScreen(), nil266+ return m.initScreen(exportView), nil283267 }284268 285269 func (m model) handleExportSubmit() (tea.Model, tea.Cmd) {@@ -341,6 +325,7 @@ func (m *model) startExport(spec packexport.Spec) tea.Cmd {
341325 m.export.running = true342326 m.state = exportRunningView343327 *m = m.clearNotice()328+ *m = m.initScreen(exportRunningView)344329 return tea.Batch(m.spinner.Tick, exportCmd(ctx, jobID, spec))345330 }346331 @@ -18,6 +18,7 @@ func (m model) handleGameSelectEnter() (tea.Model, tea.Cmd) {
1818 m.nav.modeSelectList = ui.InitList(buildModeDisplayItems(entry), entry.Definition.Name+" - Select Mode")1919 m.nav.modeSelectList.SetSize(min(m.width, 64), min(m.height, ui.ListHeight(m.nav.modeSelectList)))2020 m.state = modeSelectView21+ m = m.initScreen(modeSelectView)2122 return m, nil2223 }2324 @@ -12,5 +12,6 @@ func (m model) handleHelpSelectEnter() (tea.Model, tea.Cmd) {
1212 m.help.category = entry1313 m = m.updateHelpDetailViewport()1414 m.state = helpDetailView15+ m = m.initScreen(helpDetailView)1516 return m, nil1617 }@@ -64,5 +64,6 @@ func (m model) handleStatsEnter() (tea.Model, tea.Cmd) {
6464 )6565 m.stats.viewport.SetContent(ui.RenderStatsCardGrid(m.stats.cards, statsWidth))6666 m.state = statsView67+ m = m.initScreen(statsView)6768 return m, nil6869 }@@ -40,6 +40,7 @@ func (m model) handleThemeEnter() (tea.Model, tea.Cmd) {
4040 4141 m.state = themeSelectView4242 m = m.clearNotice()43+ m = m.initScreen(themeSelectView)4344 return m, nil4445 }4546 @@ -185,7 +185,8 @@ type seedModeOption struct {
185185 }186186 187187 type model struct {188- state viewState188+ state viewState189+ screens map[viewState]screenModel // persistent screen instances189190 190191 nav navigationState191192 cont continueState@@ -224,8 +225,9 @@ func InitialModel(s *store.Store, cfg *config.Config, configPath string) model {
224225 r := initDebugRenderer()225226 l := ui.InitCategoryList(gameCategoryItems, "Select Category")226227 mm := ui.NewMainMenu(mainMenuItems)227- return model{228+ m := model{228229 state: mainMenuView,230+ screens: make(map[viewState]screenModel),229231 debug: debugState{renderer: r},230232 nav: navigationState{gameSelectList: l, mainMenu: mm},231233 spinner: newSpinner(),@@ -233,6 +235,7 @@ func InitialModel(s *store.Store, cfg *config.Config, configPath string) model {
233235 cfg: cfg,234236 configPath: configPath,235237 }238+ return m.initScreen(mainMenuView)236239 }237240 238241 // InitialModelWithGame creates a model that starts directly in gameView,@@ -241,8 +244,9 @@ func InitialModelWithGame(s *store.Store, cfg *config.Config, configPath string,
241244 r := initDebugRenderer()242245 l := ui.InitCategoryList(gameCategoryItems, "Select Category")243246 mm := ui.NewMainMenu(mainMenuItems)244- return model{247+ m := model{245248 state: gameView,249+ screens: make(map[viewState]screenModel),246250 debug: debugState{renderer: r},247251 nav: navigationState{gameSelectList: l, mainMenu: mm},248252 spinner: newSpinner(),@@ -256,6 +260,8 @@ func InitialModelWithGame(s *store.Store, cfg *config.Config, configPath string,
256260 returnState: mainMenuView,257261 },258262 }263+ // Pre-cache the main menu screen so back-navigation from game works.264+ return m.initScreen(mainMenuView)259265 }260266 261267 func (m model) Init() tea.Cmd {@@ -19,7 +19,7 @@ func (a openPlayMenuAction) applyToModel(m model) (model, tea.Cmd) {
1919 m.nav.playMenu = ui.NewMainMenu(buildPlayMenuItems(time.Now(), m.currentWeeklyMenuIndex()))2020 m.state = playMenuView2121 m = m.clearNotice()22- return m.resizeActiveScreen(), nil22+ return m.initScreen(playMenuView), nil2323 }2424 2525 type openStatsAction struct{}@@ -34,7 +34,7 @@ func (a openOptionsMenuAction) applyToModel(m model) (model, tea.Cmd) {
3434 m.nav.optionsMenu = ui.NewMainMenu(optionsMenuItems)3535 m.state = optionsMenuView3636 m = m.clearNotice()37- return m.resizeActiveScreen(), nil37+ return m.initScreen(optionsMenuView), nil3838 }3939 4040 type quitAction struct{}@@ -49,7 +49,7 @@ func (a openGameSelectAction) applyToModel(m model) (model, tea.Cmd) {
4949 m.state = gameSelectView5050 m = m.updateCategoryDetailViewport()5151 m = m.clearNotice()52- return m.resizeActiveScreen(), nil52+ return m.initScreen(gameSelectView), nil5353 }5454 5555 type openContinueAction struct{}@@ -58,7 +58,7 @@ func (a openContinueAction) applyToModel(m model) (model, tea.Cmd) {
5858 m.cont.table, m.cont.games = ui.InitContinueTable(m.store, m.height)5959 m.state = continueView6060 m = m.clearNotice()61- return m.resizeActiveScreen(), nil61+ return m.initScreen(continueView), nil6262 }6363 6464 type openDailyAction struct{}@@ -91,7 +91,11 @@ type backAction struct {
9191 9292 func (a backAction) applyToModel(m model) (model, tea.Cmd) {9393 if m.state == themeSelectView {94- _ = theme.Apply(m.theme.previous)94+ previous := m.theme.previous95+ if ts, ok := m.screens[themeSelectView].(themeSelectScreen); ok {96+ previous = ts.theme.previous97+ }98+ _ = theme.Apply(previous)9599 }96100 m.state = a.target97101 return m.resizeActiveScreen(), nil@@ -100,18 +104,29 @@ func (a backAction) applyToModel(m model) (model, tea.Cmd) {
100104 type gameSelectEnterAction struct{}101105 102106 func (a gameSelectEnterAction) applyToModel(m model) (model, tea.Cmd) {107+ if gs, ok := m.screens[gameSelectView].(gameSelectScreen); ok {108+ m.nav.gameSelectList = gs.list109+ m.nav.categoryDetail = gs.detail110+ }103111 return asModel(m.handleGameSelectEnter())104112 }105113 106114 type modeSelectEnterAction struct{}107115 108116 func (a modeSelectEnterAction) applyToModel(m model) (model, tea.Cmd) {117+ if ms, ok := m.screens[modeSelectView].(modeSelectScreen); ok {118+ m.nav.modeSelectList = ms.list119+ m.nav.selectedCategory = ms.entry120+ }109121 return asModel(m.handleModeSelectEnter())110122 }111123 112124 type continueEnterAction struct{}113125 114126 func (a continueEnterAction) applyToModel(m model) (model, tea.Cmd) {127+ if cs, ok := m.screens[continueView].(continueScreen); ok {128+ m.cont = cs.cont129+ }115130 return asModel(m.handleContinueEnter())116131 }117132 @@ -120,19 +135,29 @@ type weeklyShiftAction struct {
120135 }121136 122137 func (a weeklyShiftAction) applyToModel(m model) (model, tea.Cmd) {138+ if ws, ok := m.screens[weeklyView].(weeklyScreen); ok {139+ m.weekly = ws.weekly140+ }123141 m = m.moveWeeklyWeek(a.delta)142+ m = m.initScreen(weeklyView)124143 return m, nil125144 }126145 127146 type weeklyEnterAction struct{}128147 129148 func (a weeklyEnterAction) applyToModel(m model) (model, tea.Cmd) {149+ if ws, ok := m.screens[weeklyView].(weeklyScreen); ok {150+ m.weekly = ws.weekly151+ }130152 return asModel(m.handleWeeklyEnter())131153 }132154 133155 type helpSelectEnterAction struct{}134156 135157 func (a helpSelectEnterAction) applyToModel(m model) (model, tea.Cmd) {158+ if hs, ok := m.screens[helpSelectView].(helpSelectScreen); ok {159+ m.help.selectList = hs.help.selectList160+ }136161 return asModel(m.handleHelpSelectEnter())137162 }138163 @@ -146,11 +171,9 @@ type openHelpSelectAction struct{}
146171 147172 func (a openHelpSelectAction) applyToModel(m model) (model, tea.Cmd) {148173 m.help.selectList = ui.InitList(gameCategoryItems, "How to Play")149- listWidth, listHeight := helpSelectListSize(m.width, m.height, m.help.selectList)150- m.help.selectList.SetSize(listWidth, listHeight)151174 m.state = helpSelectView152175 m = m.clearNotice()153- return m.resizeActiveScreen(), nil176+ return m.initScreen(helpSelectView), nil154177 }155178 156179 type previewThemeAction struct {@@ -159,19 +182,28 @@ type previewThemeAction struct {
159182 160183 func (a previewThemeAction) applyToModel(m model) (model, tea.Cmd) {161184 _ = theme.Apply(a.name)162- ui.UpdateThemeListStyles(&m.theme.list)185+ if ts, ok := m.screens[themeSelectView].(themeSelectScreen); ok {186+ ui.UpdateThemeListStyles(&ts.theme.list)187+ m.screens[themeSelectView] = ts188+ }163189 return m, nil164190 }165191 166192 type confirmThemeAction struct{}167193 168194 func (a confirmThemeAction) applyToModel(m model) (model, tea.Cmd) {195+ if ts, ok := m.screens[themeSelectView].(themeSelectScreen); ok {196+ m.theme = ts.theme197+ }169198 return asModel(m.handleThemeConfirm())170199 }171200 172201 type seedConfirmAction struct{}173202 174203 func (a seedConfirmAction) applyToModel(m model) (model, tea.Cmd) {204+ if si, ok := m.screens[seedInputView].(seedInputScreen); ok {205+ m.seed = si.seed206+ }175207 return asModel(m.handleSeedConfirm())176208 }177209 @@ -180,11 +212,9 @@ func (a seedConfirmAction) applyToModel(m model) (model, tea.Cmd) {
180212 type exportSubmitAction struct{}181213 182214 type screenModel interface {183- State() viewState184215 Resize(width, height int) screenModel185216 Update(msg tea.Msg) (screenModel, tea.Cmd, screenAction)186217 View(notice noticeState) string187- Apply(m model) model188218 }189219 190220 type screenFactory func(m model) screenModel@@ -238,9 +268,20 @@ var screenRegistry = map[viewState]screenFactory{
238268 }239269 240270 func (m model) activeScreen() screenModel {241- factory, ok := screenRegistry[m.state]271+ return m.screens[m.state]272+}273+274+// initScreen creates a fresh screen for the given state (using the registry275+// factory) and stores it in m.screens. It also calls Resize so dimensions276+// are set correctly.277+func (m model) initScreen(state viewState) model {278+ factory, ok := screenRegistry[state]242279 if !ok {243- return nil280+ return m281+ }282+ if m.screens == nil {283+ m.screens = make(map[viewState]screenModel)244284 }245- return factory(m)285+ m.screens[state] = factory(m).Resize(m.width, m.height)286+ return m246287 }@@ -13,8 +13,6 @@ type mainMenuScreen struct {
1313 menu ui.MainMenu1414 }1515 16-func (s mainMenuScreen) State() viewState { return mainMenuView }17-1816 func (s mainMenuScreen) Resize(width, height int) screenModel {1917 s.width = width2018 s.height = height@@ -48,20 +46,12 @@ func (s mainMenuScreen) View(notice noticeState) string {
4846 return centerContentWithNotice(s.width, s.height, notice, s.menu.View())4947 }5048 51-func (s mainMenuScreen) Apply(m model) model {52- m.state = mainMenuView53- m.nav.mainMenu = s.menu54- return m55-}56-5749 type playMenuScreen struct {5850 width int5951 height int6052 menu ui.MainMenu6153 }6254 63-func (s playMenuScreen) State() viewState { return playMenuView }64-6555 func (s playMenuScreen) Resize(width, height int) screenModel {6656 s.width = width6757 s.height = height@@ -100,20 +90,12 @@ func (s playMenuScreen) View(notice noticeState) string {
10090 return centerContentWithNotice(s.width, s.height, notice, s.menu.ViewAsPanel("Play"))10191 }10292 103-func (s playMenuScreen) Apply(m model) model {104- m.state = playMenuView105- m.nav.playMenu = s.menu106- return m107-}108-10993 type optionsMenuScreen struct {11094 width int11195 height int11296 menu ui.MainMenu11397 }11498 115-func (s optionsMenuScreen) State() viewState { return optionsMenuView }116-11799 func (s optionsMenuScreen) Resize(width, height int) screenModel {118100 s.width = width119101 s.height = height@@ -146,9 +128,3 @@ func (s optionsMenuScreen) View(notice noticeState) string {
146128 items := s.menu.RenderItems() + "\n\n" + ui.DimItemStyle().Render("- Dami")147129 return renderPanelView(s.width, s.height, notice, "Options", items, "↑/↓ navigate • enter select • esc back")148130 }149-150-func (s optionsMenuScreen) Apply(m model) model {151- m.state = optionsMenuView152- m.nav.optionsMenu = s.menu153- return m154-}@@ -17,8 +17,6 @@ type seedInputScreen struct {
1717 seed seedState1818 }1919 20-func (s seedInputScreen) State() viewState { return seedInputView }21-2220 func (s seedInputScreen) Resize(width, height int) screenModel {2321 s.width = width2422 s.height = height@@ -60,12 +58,6 @@ func (s seedInputScreen) View(notice noticeState) string {
6058 )6159 }6260 63-func (s seedInputScreen) Apply(m model) model {64- m.state = seedInputView65- m.seed = s.seed66- return m67-}68-6961 type gameSelectScreen struct {7062 width int7163 height int@@ -73,8 +65,6 @@ type gameSelectScreen struct {
7365 detail viewport.Model7466 }7567 76-func (s gameSelectScreen) State() viewState { return gameSelectView }77-7868 func (s gameSelectScreen) Resize(width, height int) screenModel {7969 m := model{8070 width: width,@@ -139,13 +129,6 @@ func (s gameSelectScreen) View(notice noticeState) string {
139129 return m.gameSelectViewContent()140130 }141131 142-func (s gameSelectScreen) Apply(m model) model {143- m.state = gameSelectView144- m.nav.gameSelectList = s.list145- m.nav.categoryDetail = s.detail146- return m147-}148-149132 func (s gameSelectScreen) resizeSelf() gameSelectScreen {150133 return s.Resize(s.width, s.height).(gameSelectScreen)151134 }@@ -157,8 +140,6 @@ type modeSelectScreen struct {
157140 list list.Model158141 }159142 160-func (s modeSelectScreen) State() viewState { return modeSelectView }161-162143 func (s modeSelectScreen) Resize(width, height int) screenModel {163144 s.width = width164145 s.height = height@@ -199,21 +180,12 @@ func (s modeSelectScreen) View(notice noticeState) string {
199180 )200181 }201182 202-func (s modeSelectScreen) Apply(m model) model {203- m.state = modeSelectView204- m.nav.selectedCategory = s.entry205- m.nav.modeSelectList = s.list206- return m207-}208-209183 type continueScreen struct {210184 width int211185 height int212186 cont continueState213187 }214188 215-func (s continueScreen) State() viewState { return continueView }216-217189 func (s continueScreen) Resize(width, height int) screenModel {218190 s.width = width219191 s.height = height@@ -249,20 +221,12 @@ func (s continueScreen) View(notice noticeState) string {
249221 return m.renderContinueView()250222 }251223 252-func (s continueScreen) Apply(m model) model {253- m.state = continueView254- m.cont = s.cont255- return m256-}257-258224 type weeklyScreen struct {259225 width int260226 height int261227 weekly weeklyState262228 }263229 264-func (s weeklyScreen) State() viewState { return weeklyView }265-266230 func (s weeklyScreen) Resize(width, height int) screenModel {267231 s.width = width268232 s.height = height@@ -301,9 +265,3 @@ func (s weeklyScreen) View(notice noticeState) string {
301265 }302266 return centerContentWithNotice(s.width, s.height, notice, m.weeklyViewContent())303267 }304-305-func (s weeklyScreen) Apply(m model) model {306- m.state = weeklyView307- m.weekly = s.weekly308- return m309-}@@ -16,8 +16,6 @@ type helpSelectScreen struct {
1616 help helpState1717 }1818 19-func (s helpSelectScreen) State() viewState { return helpSelectView }20-2119 func (s helpSelectScreen) Resize(width, height int) screenModel {2220 s.width = width2321 s.height = height@@ -56,20 +54,12 @@ func (s helpSelectScreen) View(notice noticeState) string {
5654 )5755 }5856 59-func (s helpSelectScreen) Apply(m model) model {60- m.state = helpSelectView61- m.help.selectList = s.help.selectList62- return m63-}64-6557 type helpDetailScreen struct {6658 width int6759 height int6860 help helpState6961 }7062 71-func (s helpDetailScreen) State() viewState { return helpDetailView }72-7363 func (s helpDetailScreen) Resize(width, height int) screenModel {7464 m := model{7565 width: width,@@ -108,20 +98,12 @@ func (s helpDetailScreen) View(notice noticeState) string {
10898 )10999 }110100 111-func (s helpDetailScreen) Apply(m model) model {112- m.state = helpDetailView113- m.help = s.help114- return m115-}116-117101 type statsScreen struct {118102 width int119103 height int120104 stats statsState121105 }122106 123-func (s statsScreen) State() viewState { return statsView }124-125107 func (s statsScreen) Resize(width, height int) screenModel {126108 m := model{127109 width: width,@@ -156,20 +138,12 @@ func (s statsScreen) View(notice noticeState) string {
156138 return m.renderStatsView()157139 }158140 159-func (s statsScreen) Apply(m model) model {160- m.state = statsView161- m.stats = s.stats162- return m163-}164-165141 type themeSelectScreen struct {166142 width int167143 height int168144 theme themeState169145 }170146 171-func (s themeSelectScreen) State() viewState { return themeSelectView }172-173147 func (s themeSelectScreen) Resize(width, height int) screenModel {174148 const maxVisibleItems = 8175149 menuW := min(width, 64)@@ -217,20 +191,12 @@ func (s themeSelectScreen) View(notice noticeState) string {
217191 return m.themeSelectViewContent()218192 }219193 220-func (s themeSelectScreen) Apply(m model) model {221- m.state = themeSelectView222- m.theme = s.theme223- return m224-}225-226194 type generatingScreen struct {227195 width int228196 height int229197 spinner spinner.Model230198 }231199 232-func (s generatingScreen) State() viewState { return generatingView }233-234200 func (s generatingScreen) Resize(width, height int) screenModel {235201 s.width = width236202 s.height = height@@ -248,9 +214,3 @@ func (s generatingScreen) View(notice noticeState) string {
248214 box := ui.GeneratingFrame().Render(appendNoticeContent(s.width, notice, content))249215 return ui.CenterView(s.width, s.height, box)250216 }251-252-func (s generatingScreen) Apply(m model) model {253- m.state = generatingView254- m.spinner = s.spinner255- return m256-}@@ -82,6 +82,7 @@ func (m model) enterSeedInputView() (model, tea.Cmd) {
8282 m.seed.modeIndex = index8383 m.seed.focus = seedFocusText8484 m.state = seedInputView85+ m = m.initScreen(seedInputView)8586 return m, m.seed.input.Focus()8687 }8788 @@ -46,6 +46,7 @@ func (c sessionController) startSpawn(spawner game.Spawner, request spawnRequest
4646 c.model.session.spawn = &request4747 c.model.state = generatingView4848 *c.model = c.model.clearNotice()49+ *c.model = c.model.initScreen(generatingView)4950 return tea.Batch(c.model.spinner.Tick, spawnCmd(spawner, ctx, jobID))5051 }5152 @@ -54,6 +55,7 @@ func (c sessionController) startSeededSpawn(spawner game.SeededSpawner, rng *ran
5455 c.model.session.spawn = &request5556 c.model.state = generatingView5657 *c.model = c.model.clearNotice()58+ *c.model = c.model.initScreen(generatingView)5759 return tea.Batch(c.model.spinner.Tick, spawnSeededCmd(spawner, rng, ctx, jobID))5860 }5961 @@ -46,7 +46,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
4646 }4747 4848 nextScreen, screenCmd, action := screen.Update(msg)49- m = nextScreen.Apply(m)49+ if m.screens == nil {50+ m.screens = make(map[viewState]screenModel)51+ }52+ m.screens[m.state] = nextScreen5053 if action == nil {5154 return m, screenCmd5255 }@@ -56,11 +59,12 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
5659 }5760 5861 func (m model) resizeActiveScreen() model {59- screen := m.activeScreen()62+ screen := m.screens[m.state] // nil map read is safe; returns nil6063 if screen == nil {6164 return m6265 }63- return screen.Resize(m.width, m.height).Apply(m)66+ m.screens[m.state] = screen.Resize(m.width, m.height)67+ return m6468 }6569 6670 func (m model) handleWindowSize(msg tea.WindowSizeMsg) model {@@ -116,6 +120,7 @@ func (m model) handleGlobalKey(msg tea.Msg) (model, tea.Cmd, bool) {
116120 m.state = returnState117121 if returnState == weeklyView {118122 m = m.refreshWeeklyBrowser()123+ m = m.initScreen(weeklyView)119124 }120125 m.debug.enabled = false121126 return m, nil, true@@ -239,20 +239,25 @@ func TestSeedInputSelectorCyclesAndPersistsDefault(t *testing.T) {
239239 focus: seedFocusMode,240240 },241241 }242+ m = m.initScreen(seedInputView)242243 243244 next, _ := m.Update(tea.KeyPressMsg{Code: tea.KeyRight})244245 got := next.(model)245246 246- if got.seed.modeIndex != 1 {247- t.Fatalf("seedModeIndex = %d, want 1", got.seed.modeIndex)247+ si, ok := got.screens[seedInputView].(seedInputScreen)248+ if !ok {249+ t.Fatal("expected seedInputView screen to be cached")250+ }251+ if si.seed.modeIndex != 1 {252+ t.Fatalf("seedModeIndex = %d, want 1", si.seed.modeIndex)248253 }249- if got.seed.lastModeKey != options[1].key {250- t.Fatalf("lastSeedModeKey = %q, want %q", got.seed.lastModeKey, options[1].key)254+ if si.seed.lastModeKey != options[1].key {255+ t.Fatalf("lastSeedModeKey = %q, want %q", si.seed.lastModeKey, options[1].key)251256 }252257 253258 reopenedModel, _ := (model{254259 state: playMenuView,255- seed: seedState{lastModeKey: got.seed.lastModeKey},260+ seed: seedState{lastModeKey: si.seed.lastModeKey},256261 }).enterSeedInputView()257262 258263 if reopenedModel.state != seedInputView {@@ -371,6 +376,7 @@ func TestGameSelectEscapeClearsAppliedFilterBeforeLeavingView(t *testing.T) {
371376 gameSelectList: l,372377 },373378 }379+ m = m.initScreen(gameSelectView)374380 375381 next, _ := m.Update(tea.KeyPressMsg{Code: tea.KeyEscape})376382 got := next.(model)@@ -378,8 +384,12 @@ func TestGameSelectEscapeClearsAppliedFilterBeforeLeavingView(t *testing.T) {
378384 if got.state != gameSelectView {379385 t.Fatalf("state = %d, want %d (gameSelectView)", got.state, gameSelectView)380386 }381- if got.nav.gameSelectList.FilterState() != list.Unfiltered {382- t.Fatalf("filter state = %s, want %s", got.nav.gameSelectList.FilterState(), list.Unfiltered)387+ gs, ok := got.screens[gameSelectView].(gameSelectScreen)388+ if !ok {389+ t.Fatal("expected gameSelectView screen to be cached")390+ }391+ if gs.list.FilterState() != list.Unfiltered {392+ t.Fatalf("filter state = %s, want %s", gs.list.FilterState(), list.Unfiltered)383393 }384394 }385395 No content changes.
@@ -34,6 +34,7 @@ func TestPlayMenuViewIncludesNotice(t *testing.T) {
3434 },3535 notice: noticeState{level: noticeLevelError, message: "Could not load puzzle"},3636 }37+ m = m.initScreen(playMenuView)3738 3839 if got := m.viewContent(); !strings.Contains(got, "Could not load puzzle") {3940 t.Fatalf("viewContent() missing notice, got %q", got)@@ -42,6 +42,7 @@ func (m model) enterWeeklyView() (tea.Model, tea.Cmd) {
4242 m.weekly.cursor = weekly.StartOfWeek(current.Year, current.Week, time.Local)4343 m = m.refreshWeeklyBrowser()4444 m.state = weeklyView45+ m = m.initScreen(weeklyView)4546 return m, nil4647 }4748 @@ -182,6 +183,7 @@ func (m model) advanceSolvedWeekly() (model, tea.Cmd, bool) {
182183 m.weekly.cursor = weekly.StartOfWeek(info.Year, info.Week, time.Local)183184 m = m.refreshWeeklyBrowser()184185 m.state = weeklyView186+ m = m.initScreen(weeklyView)185187 if len(m.weekly.rows) == 0 || !m.weekly.rows[0].Playable {186188 return m, nil, true187189 }