|
| 1 | +# ScreenManager Architecture |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +The ScreenManager is a centralized system for managing screen transitions, rendering loops, input handling, and terminal lifecycle in GitType. This architecture provides a unified approach for handling all screen-related operations and supports both crossterm and ratatui rendering backends. |
| 6 | + |
| 7 | +## Key Components |
| 8 | + |
| 9 | +### ScreenManager |
| 10 | + |
| 11 | +The core component that coordinates all screen operations: |
| 12 | + |
| 13 | +```rust |
| 14 | +pub struct ScreenManager { |
| 15 | + screens: HashMap<ScreenType, Box<dyn Screen>>, |
| 16 | + screen_stack: Vec<ScreenType>, |
| 17 | + current_screen_type: ScreenType, |
| 18 | + should_exit: bool, |
| 19 | + terminal_initialized: bool, |
| 20 | + last_update: Instant, |
| 21 | + render_backend: RenderBackend, |
| 22 | +} |
| 23 | +``` |
| 24 | + |
| 25 | +Features: |
| 26 | +- **Centralized Rendering Loop**: ScreenManager owns and manages the main rendering loop |
| 27 | +- **Input Handling**: ScreenManager handles all keyboard input events and dispatches to current screen |
| 28 | +- **Screen Management**: Uses screen stack for nested screens/dialogs |
| 29 | +- **Terminal Lifecycle**: Manages raw mode, cursor visibility, and alternate screen |
| 30 | +- **Dual Rendering Support**: Supports both crossterm and ratatui backends |
| 31 | + |
| 32 | +### Screen Trait |
| 33 | + |
| 34 | +All screens implement the `Screen` trait: |
| 35 | + |
| 36 | +```rust |
| 37 | +pub trait Screen: Send { |
| 38 | + fn init(&mut self) -> Result<()>; |
| 39 | + fn handle_key_event(&mut self, key_event: KeyEvent) -> Result<ScreenTransition>; |
| 40 | + fn render_crossterm(&self, stdout: &mut Stdout) -> Result<()>; |
| 41 | + fn render_ratatui(&self, _frame: &mut ratatui::Frame) -> Result<()>; |
| 42 | + fn cleanup(&mut self) -> Result<()>; |
| 43 | + fn should_exit(&self) -> bool; |
| 44 | + fn get_update_strategy(&self) -> UpdateStrategy; |
| 45 | + fn update(&mut self) -> Result<bool>; |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +### Update Strategy System |
| 50 | + |
| 51 | +Screens can define how they should be updated: |
| 52 | + |
| 53 | +```rust |
| 54 | +pub enum UpdateStrategy { |
| 55 | + InputOnly, // Update only on input events |
| 56 | + TimeBased(Duration), // Update at regular intervals |
| 57 | + Hybrid { // Both input and time-based |
| 58 | + interval: Duration, |
| 59 | + input_priority: bool, |
| 60 | + }, |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +#### Strategy Examples: |
| 65 | +- **Title Screen**: `InputOnly` - Only updates when user presses keys |
| 66 | +- **Loading Screen**: `TimeBased(Duration::from_millis(100))` - Updates progress regularly |
| 67 | +- **Typing Screen**: `Hybrid { interval: Duration::from_millis(500), input_priority: true }` - Updates on input + cursor blink |
| 68 | +- **Animation Screen**: `TimeBased(Duration::from_millis(50))` - Smooth animation updates |
| 69 | + |
| 70 | +### Screen Types |
| 71 | + |
| 72 | +```rust |
| 73 | +pub enum ScreenType { |
| 74 | + Title, Loading, Typing, StageSummary, SessionSummary, |
| 75 | + ExitSummary, Cancel, Failure, History, Analytics, |
| 76 | + SessionDetail, Sharing, Animation, VersionCheck, |
| 77 | + InfoDialog, DetailsDialog, |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +### Screen Transitions |
| 82 | + |
| 83 | +```rust |
| 84 | +pub enum ScreenTransition { |
| 85 | + None, // No transition |
| 86 | + Push(ScreenType), // Push new screen onto stack |
| 87 | + Pop, // Pop current screen from stack |
| 88 | + Replace(ScreenType), // Replace current screen |
| 89 | + PopTo(ScreenType), // Pop until reaching specific screen |
| 90 | + Exit, // Exit application |
| 91 | +} |
| 92 | +``` |
| 93 | + |
| 94 | +## Usage Example |
| 95 | + |
| 96 | +```rust |
| 97 | +use gittype::game::{BasicScreen, ScreenManager, ScreenType, UpdateStrategy}; |
| 98 | + |
| 99 | +fn main() -> gittype::Result<()> { |
| 100 | + let mut screen_manager = ScreenManager::new(); |
| 101 | + |
| 102 | + // Create a screen with input-only updates |
| 103 | + let title_screen = BasicScreen::new( |
| 104 | + "My App".to_string(), |
| 105 | + vec!["Welcome!".to_string()], |
| 106 | + UpdateStrategy::InputOnly, |
| 107 | + ); |
| 108 | + |
| 109 | + // Register the screen |
| 110 | + screen_manager.register_screen(ScreenType::Title, Box::new(title_screen)); |
| 111 | + |
| 112 | + // Run the application |
| 113 | + screen_manager.run()?; |
| 114 | + |
| 115 | + Ok(()) |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +## Benefits |
| 120 | + |
| 121 | +1. **Maintainability**: Centralized control makes code easier to understand and modify |
| 122 | +2. **Consistency**: All screens follow the same patterns and lifecycle |
| 123 | +3. **Performance**: Single rendering loop reduces overhead and improves responsiveness |
| 124 | +4. **Extensibility**: Adding new screens becomes straightforward with clear interfaces |
| 125 | +5. **Testing**: Easier to unit test individual screens and transitions |
| 126 | +6. **Error Handling**: Centralized error handling for screen-related issues |
| 127 | +7. **Flexibility**: Support for different rendering backends and update strategies |
| 128 | +8. **Terminal Stability**: Reduced terminal configuration overhead and more stable terminal state |
| 129 | +9. **Power Efficiency**: Screens can optimize their update frequency based on needs |
| 130 | + |
| 131 | +## Implementation Strategy |
| 132 | + |
| 133 | +### Phase 1: Core Architecture ✅ |
| 134 | +- [x] Create `ScreenManager` with rendering loop and input handling |
| 135 | +- [x] Define `Screen` trait with dual rendering support and update strategies |
| 136 | +- [x] Implement `ScreenType` enum and transition system |
| 137 | +- [x] Add terminal lifecycle management |
| 138 | + |
| 139 | +### Phase 2: Update Strategy System ✅ |
| 140 | +- [x] Implement `UpdateStrategy` enum and logic |
| 141 | +- [x] Create timer-based update mechanism for time-driven screens |
| 142 | +- [x] Add hybrid update support for complex screens |
| 143 | +- [x] Optimize rendering pipeline to avoid unnecessary updates |
| 144 | + |
| 145 | +### Phase 3: Screen Migration (In Progress) |
| 146 | +- [ ] Refactor existing screens to implement new `Screen` trait |
| 147 | +- [ ] Move rendering logic to use centralized system |
| 148 | +- [ ] Update input handling to use event dispatching |
| 149 | +- [ ] Assign appropriate update strategies to each screen |
| 150 | + |
| 151 | +### Phase 4: Integration (Planned) |
| 152 | +- [ ] Integrate ScreenManager into StageManager |
| 153 | +- [ ] Remove duplicate rendering and input code |
| 154 | +- [ ] Test all screen transitions and functionality |
| 155 | +- [ ] Optimize terminal initialization/cleanup |
| 156 | + |
| 157 | +### Phase 5: Optimization (Planned) |
| 158 | +- [ ] Performance tuning of rendering loop |
| 159 | +- [ ] Add ratatui rendering implementations |
| 160 | +- [ ] Fine-tune update strategies for optimal performance |
| 161 | +- [ ] Documentation and testing |
| 162 | + |
| 163 | +## Best Practices |
| 164 | + |
| 165 | +1. **Screen Lifecycle**: Always implement proper init/cleanup in screens |
| 166 | +2. **Update Strategy**: Choose the most appropriate update strategy for each screen |
| 167 | +3. **Error Handling**: Handle errors gracefully in screen implementations |
| 168 | +4. **Resource Management**: Clean up resources in the cleanup method |
| 169 | +5. **Performance**: Avoid unnecessary renders by returning `false` from `update()` when no changes occur |
| 170 | +6. **Input Handling**: Use screen transitions to control navigation flow |
| 171 | +7. **Testing**: Test screens individually and integration with ScreenManager |
| 172 | + |
| 173 | +## Migration Guide |
| 174 | + |
| 175 | +To migrate existing screens to the new architecture: |
| 176 | + |
| 177 | +1. Implement the `Screen` trait for your screen struct |
| 178 | +2. Move rendering logic to `render_crossterm()` method |
| 179 | +3. Move input handling to `handle_key_event()` method |
| 180 | +4. Define appropriate `UpdateStrategy` in `get_update_strategy()` |
| 181 | +5. Register screen with ScreenManager |
| 182 | +6. Remove old direct terminal management code |
| 183 | + |
| 184 | +This architecture provides a solid foundation for building complex terminal applications with proper separation of concerns and consistent behavior across all screens. |
0 commit comments