Skip to content

feat: add optional boot splash settings#224

Merged
nathanhuh merged 3 commits into
mainfrom
feat/222-bootup-splash
Jun 2, 2026
Merged

feat: add optional boot splash settings#224
nathanhuh merged 3 commits into
mainfrom
feat/222-bootup-splash

Conversation

@nathanhuh

@nathanhuh nathanhuh commented May 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a smooth retro boot splash that appears once per new app version by default.
  • Store boot splash preference and last-seen version in config.
  • Add a Settings screen opened with S for app-level preferences.
  • Keep context picker focused on context workflows.

Related Issues

Closes #222

Validation

  • make test
  • make build

Checklist

  • Scope is focused
  • Branch name follows docs/branch-naming-harness.md
  • Documentation harness reviewed (docs/documentation-harness.md)
  • README updated if user-facing behavior changed
  • Relevant docs/ pages updated if architecture, auth, config, or workflow changed
  • Tests/validation included
  • Breaking changes documented

Summary by CodeRabbit

Release Notes

  • New Features

    • Boot splash screen now appears after app install or update; press Enter to skip
    • Settings menu added (press "S") to toggle boot splash visibility per launch
  • Documentation

    • Keyboard shortcuts updated to document the new Settings feature and related shortcuts

- add smooth retro boot splash shown once per new app version
- add config-backed Settings screen for boot splash preference
- keep context picker focused on context workflows

Closes #222
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@nathanhuh, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 16 minutes and 42 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9fae524e-d4f7-419a-a224-7aa1d2c9a5c5

📥 Commits

Reviewing files that changed from the base of the PR and between ec9414c and 7cba12c.

📒 Files selected for processing (9)
  • internal/app/app.go
  • internal/app/app_test.go
  • internal/app/messages.go
  • internal/app/screen_bootup.go
  • internal/app/screen_context.go
  • internal/app/screen_settings.go
  • internal/app/service_list.go
  • internal/config/config.go
  • internal/config/config_test.go

Walkthrough

This PR implements a quirky 80s-style bootup splash animation that displays briefly during TUI startup, with optional configuration to disable or always show it. A new Settings screen lets users toggle the preference per launch. The startup sequence, context loading, and global navigation are updated to accommodate the bootup screen flow.

Changes

TUI Boot Splash & Settings

Layer / File(s) Summary
Boot Splash Configuration Schema & Persistence
internal/config/config.go, internal/config/config_test.go
Config gains ui block with boot_splash and last_boot_splash_version fields. Load/LoadNamedContext map these to Config struct. New SetBootSplashEnabled and SetBootSplashSeenVersion setters persist state to YAML with fallback/merge logic. Tests verify load behavior and preservation of existing config during updates.
Boot Splash Screen Rendering
internal/app/screen_bootup.go
Implements bootup view with BIOS header, frame-animated ASCII logo (character-by-character fill), progress bar with status label, and diagnostic step list (incrementally revealed). Output centered vertically within model height with optional width constraint.
Settings Screen Implementation
internal/app/screen_settings.go
New UI screen with navigable settings list. settingsItem model maps bootSplash state to displayable name/value/description. Input handlers support navigation (arrow/vim keys), toggle (Enter/Space), and back-navigation (Esc/q). Renders status bar, title, cursor-prefixed items, and help text. Toggling invokes toggleBootSplash or transitions to error screen.
Application Boot Lifecycle & Message Types
internal/app/messages.go, internal/app/app.go, internal/app/app_test.go
Three new message types mark screen readiness and bootup tick events. Model.bootSplash field controls splash visibility. Init() refactored with tea.Sequence: conditionally runs bootup before context picker based on shouldShowBootup() (version/preference state). Update() handlers manage bootFrame animation counter and screen transitions. View() renders bootup screen. Tests cover animation, context loading concurrency, tick/skip transitions, visibility rules, and layout centering.
Settings & Boot Splash Toggle Control
internal/app/service_list.go, internal/app/app_test.go
toggleBootSplash() method on Model flips bootSplash state, syncs in-memory config, and persists via config setter. Config function variables (configSetBootSplashEnabledFn, configSetBootSplashSeenVersionFn) allow test injection. Test verifies toggle updates both model and persisted config.
Navigation, Shortcuts & Help System
internal/app/app.go, internal/app/screen_context.go, internal/app/help.go, internal/app/app_test.go
Global S key shortcut (guarded by filter/screen state) opens Settings and stores previous screen. Update() dispatches screenSettings; View() renders it. Context picker respects bootSplash state (no forced transition during splash); help bar gains S: settings; filter keys support S. Help system adds S shortcut conditional, screenSettings case with movement/toggle/back hints, and help title mapping. Tests verify S shortcut navigation, settings view rendering, and integration.
User Documentation
README.md
Documents bootup splash behavior (post-install/update, skippable), new S key for Settings, ui config block schema, and keyboard shortcuts table with Settings row.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.21% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat: add optional boot splash settings' follows conventional commit format and accurately summarizes the main feature added.
Description check ✅ Passed The PR description covers all required sections: Summary, Related Issues, Validation, and Checklist with all items marked complete.
Linked Issues check ✅ Passed The code changes fully address issue #222 requirements: boot splash screen implemented with animation, context loading continues, users can skip, comprehensive tests added, and README updated.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #222: boot splash feature, settings screen, configuration persistence, and related tests. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/222-bootup-splash

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@amazon-q-developer amazon-q-developer Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR successfully adds a configurable retro bootup splash screen feature with proper settings integration. The implementation is clean and well-structured:

  • Bootup animation renders correctly with frame-based progression
  • Settings screen allows toggling the splash on/off
  • Config persistence works properly with YAML marshaling
  • State management flows correctly through the TUI lifecycle
  • Error handling is appropriate throughout

No blocking defects found. The code is ready to merge.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/app/app_test.go`:
- Around line 236-263: Add a new test (e.g.,
TestSettingsTogglesBootSplashPreference_Error) that mirrors
TestSettingsTogglesBootSplashPreference but makes configSetBootSplashEnabledFn
return a non-nil error; instantiate the model with New(cfg, "config.yaml",
"dev"), set m.screen = screenSettings, call m.Update(tea.KeyMsg{Type:
tea.KeyEnter}) and assert the returned Model has m.screen == screenError (or the
exported equivalent) and that the error branch is taken (check any error
message/state on Model), and ensure you restore the original
configSetBootSplashEnabledFn in a defer just like the existing test to avoid
cross-test pollution.

In `@internal/app/app.go`:
- Around line 486-493: The global uppercase "S" shortcut handler is firing
before screen-specific input and should skip screens that accept text entry
(e.g., screenContextAdd) so it doesn't steal input; update the conditional that
checks msg.String() == "S" and m.filterTI.Focused() to also exclude text-entry
screens by adding checks like m.screen != screenContextAdd (and any other
text-entry screens) before calling m.deactivateFilter(), setting
m.settingsPrevScreen and switching to screenSettings, ensuring screen-specific
input handlers still receive the key.

In `@internal/app/screen_bootup.go`:
- Line 17: Replace the hardcoded banner string passed to dimStyle.Render with a
formatted string that uses the model's currentVersion (m.currentVersion) and
falls back to a sensible default (e.g., "v0.0.0" or "unknown") when
m.currentVersion is empty; locate the call to dimStyle.Render in
screen_bootup.go and change it to construct the banner using m.currentVersion so
the splash header reflects the actual app version at runtime.

In `@internal/app/screen_context.go`:
- Around line 40-42: The handler is overwriting active screens during background
startup because it unconditionally sets m.screen = screenContextPicker when
m.screen != screenBootup; instead, change the message from loadContexts() to
carry an explicit startup flag (e.g., contextsLoadedMsg{startup bool}) and only
switch screens when the loadContexts result is from startup and the model is
still on boot (e.g., if msg.startup && m.screen == screenBootup then m.screen =
screenContextPicker); do not change m.screen for non-startup loads so
user-opened screens like Settings aren't bounced.

In `@internal/app/screen_settings.go`:
- Around line 66-77: The current fmt.Sprintf call pads ANSI escape sequences
instead of visible widths; replace the fmt.Sprintf usage in the loop over items
with lipgloss width-aware rendering: build a name cell using
nameStyle.Copy().Width(18).Render(item.name) (or
lipgloss.NewStyle().Width(18).Render(nameStyle.Render(item.name))) and a value
cell via valueStyle.Render(item.value), then write the row with
panel.WriteString(prefix + nameCell + " " + valueCell + "\n"); keep the
description line using dimStyle.Render(item.description) as before and preserve
the selection logic that sets prefix/nameStyle/valueStyle when i ==
m.settingsIdx.

In `@internal/app/service_list.go`:
- Around line 89-99: The toggleBootSplash function currently flips m.bootSplash
and m.cfg.BootSplash before persisting; change it to compute the desired new
value first (e.g., newVal := !m.bootSplash), call
configSetBootSplashEnabledFn(m.configPath, newVal) and only on success assign
m.bootSplash = newVal and if m.cfg != nil set m.cfg.BootSplash = newVal; keep
the existing configPath empty-string check and return any error from
configSetBootSplashEnabledFn without mutating in-memory state.

In `@internal/config/config_test.go`:
- Around line 179-217: Add a regression test that verifies disabling boot splash
survives save/load: call writeUnicConfig to create a base config (preserving an
existing field like default_region), invoke SetBootSplashEnabled(path, false),
then Load(nil, nil, path) and assert cfg.BootSplash is false and other fields
(e.g. cfg.Region) are preserved; place this alongside
TestSetBootSplashEnabledWritesConfig and
TestSetBootSplashSeenVersionWritesConfig to catch the YAML-contract
explicit-disable bug affecting SetBootSplashEnabled and the BootSplash field
round-trip.

In `@internal/config/config.go`:
- Around line 41-44: The fileUI struct's BootSplash boolean uses `omitempty`,
collapsing "unset" and "false" and preventing Load and SetBootSplashEnabled from
distinguishing an explicit disable; change BootSplash to a tri-state (e.g.,
*bool) so nil = unset, true/false = explicit, and remove omitempty only when you
truly want to omit unset; update any related structs/fields mentioned around
lines 74-87 and 638-655 to the same tri-state pattern, and adjust
SetBootSplashEnabled, Load (and any marshal/unmarshal logic) to handle nil as
"use default behavior" while true/false represent explicit choices. Ensure
LastBootSplashVersion remains a string but keep BootSplash as *bool to preserve
explicit disabled state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8376f7f8-8274-4c99-ab4e-acf35de8af1b

📥 Commits

Reviewing files that changed from the base of the PR and between 8feb593 and ec9414c.

📒 Files selected for processing (11)
  • README.md
  • internal/app/app.go
  • internal/app/app_test.go
  • internal/app/help.go
  • internal/app/messages.go
  • internal/app/screen_bootup.go
  • internal/app/screen_context.go
  • internal/app/screen_settings.go
  • internal/app/service_list.go
  • internal/config/config.go
  • internal/config/config_test.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (4)
**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.go: Use lipgloss for styled TUI output — column-aligned tables with dimmed labels in Go implementation files
Implement scroll windowing with formula: visibleLines := max(m.height-N, 5) in Go TUI implementation

Files:

  • internal/app/messages.go
  • internal/app/service_list.go
  • internal/config/config_test.go
  • internal/app/screen_settings.go
  • internal/app/screen_bootup.go
  • internal/config/config.go
  • internal/app/help.go
  • internal/app/app.go
  • internal/app/screen_context.go
  • internal/app/app_test.go

⚙️ CodeRabbit configuration file

**/*.go: For Go reviews, look beyond compilation and prioritize nil pointer risks,
context propagation, AWS SDK pagination, error wrapping, deterministic
sorting, and stable table/detail rendering. For new AWS service work,
verify that repository interfaces, model mapping, app integration, and
tests are updated together.

Files:

  • internal/app/messages.go
  • internal/app/service_list.go
  • internal/config/config_test.go
  • internal/app/screen_settings.go
  • internal/app/screen_bootup.go
  • internal/config/config.go
  • internal/app/help.go
  • internal/app/app.go
  • internal/app/screen_context.go
  • internal/app/app_test.go
internal/app/**

⚙️ CodeRabbit configuration file

internal/app/**: For Bubble Tea screen changes, verify message routing, key handling,
filter target resets, height-based windowing, help text, and back/home
navigation against the existing screen patterns.

Files:

  • internal/app/messages.go
  • internal/app/service_list.go
  • internal/app/screen_settings.go
  • internal/app/screen_bootup.go
  • internal/app/help.go
  • internal/app/app.go
  • internal/app/screen_context.go
  • internal/app/app_test.go
README.md

📄 CodeRabbit inference engine (CLAUDE.md)

README.md: When adding, modifying, or deleting features, always update README.md in parallel with code changes
Update Currently Implemented Features table in README.md: add new services/features, update status changes (🚧→✅), remove deleted items
Update TUI Key Bindings table in README.md when key bindings are added, changed, or deleted
Update Usage section in README.md when new CLI commands or flags are added
Update Configuration section in README.md when configuration format changes

Files:

  • README.md

⚙️ CodeRabbit configuration file

README.md: Verify that README changes match actual CLI/TUI behavior and that
Currently Implemented Features, TUI Key Bindings, Usage, and
Configuration content stay aligned with code changes.

Files:

  • README.md
**/*_test.go

📄 CodeRabbit inference engine (CLAUDE.md)

Tests use mock client interfaces (see rds_test.go pattern) in Go test files

Files:

  • internal/config/config_test.go
  • internal/app/app_test.go

⚙️ CodeRabbit configuration file

**/*_test.go: Check that tests cover API errors, mapping edge cases, and navigation
state transitions, not only happy paths. Prefer mock-based tests that do
not depend on external AWS calls.

Files:

  • internal/config/config_test.go
  • internal/app/app_test.go

Comment thread internal/app/app_test.go
Comment thread internal/app/app.go
Comment thread internal/app/screen_bootup.go Outdated
Comment thread internal/app/screen_context.go Outdated
Comment thread internal/app/screen_settings.go
Comment thread internal/app/service_list.go
Comment thread internal/config/config_test.go
Comment thread internal/config/config.go
@nathanhuh nathanhuh merged commit 0b33442 into main Jun 2, 2026
2 checks passed
@nathanhuh nathanhuh deleted the feat/222-bootup-splash branch June 2, 2026 09:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add 80s-style TUI bootup splash animation

2 participants