chore: move each view used in BottomPane into its own file (#928)

`BottomPane` was getting a bit unwieldy because it maintained a
`PaneState` enum with three variants and many of its methods had `match`
statements to handle each variant. To replace the enum, this PR:

* Introduces a `trait BottomPaneView` that has two implementations:
`StatusIndicatorView` and `ApprovalModalView`.
* Migrates `PaneState::TextInput` into its own struct, `ChatComposer`,
that does **not** implement `BottomPaneView`.
* Updates `BottomPane` so it has `composer: ChatComposer` and
`active_view: Option<Box<dyn BottomPaneView<'a> + 'a>>`. The idea is
that `active_view` takes priority and is displayed when it is `Some`;
otherwise, `ChatComposer` is displayed.
* While methods of `BottomPane` often have to check whether
`active_view` is present to decide which component to delegate to, the
code is more straightforward than before and introducing new
implementations of `BottomPaneView` should be less painful.

Because we want to retain the `TextArea` owned by `ChatComposer` even
when another view is displayed, to keep the ownership logic simple, it
seemed best to keep `ChatComposer` distinct from `BottomPaneView`.
This commit is contained in:
Michael Bolin
2025-05-14 10:13:29 -07:00
committed by GitHub
parent 399e819c9b
commit 0402aef126
8 changed files with 490 additions and 358 deletions

View File

@@ -0,0 +1,57 @@
use std::sync::mpsc::SendError;
use std::sync::mpsc::Sender;
use crossterm::event::KeyEvent;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::widgets::WidgetRef;
use crate::app_event::AppEvent;
use crate::status_indicator_widget::StatusIndicatorWidget;
use super::BottomPane;
use super::BottomPaneView;
use super::bottom_pane_view::ConditionalUpdate;
pub(crate) struct StatusIndicatorView {
view: StatusIndicatorWidget,
}
impl StatusIndicatorView {
pub fn new(app_event_tx: Sender<AppEvent>, height: u16) -> Self {
Self {
view: StatusIndicatorWidget::new(app_event_tx, height),
}
}
pub fn update_text(&mut self, text: String) {
self.view.update_text(text);
}
}
impl<'a> BottomPaneView<'a> for StatusIndicatorView {
fn handle_key_event(
&mut self,
_pane: &mut BottomPane<'a>,
_key_event: KeyEvent,
) -> Result<(), SendError<AppEvent>> {
Ok(())
}
fn update_status_text(&mut self, text: String) -> ConditionalUpdate {
self.update_text(text);
ConditionalUpdate::NeedsRedraw
}
fn should_hide_when_task_is_done(&mut self) -> bool {
true
}
fn calculate_required_height(&self, _area: &Rect) -> u16 {
self.view.get_height()
}
fn render(&self, area: Rect, buf: &mut Buffer) {
self.view.render_ref(area, buf);
}
}