use std::rc::Rc;
use ratatui::{crossterm::event::KeyEvent, layout::Rect, Frame};
use crate::{
app::AppContext,
event::{Sender, UserEventWithCount},
git::{Commit, FileChange, Ref},
view::{
detail::DetailView, help::HelpView, list::ListView, refs::RefsView,
user_command::UserCommandView,
},
widget::commit_list::CommitListState,
};
#[derive(Debug, Default)]
pub enum View<'a> {
#[default]
Default, List(Box<ListView<'a>>),
Detail(Box<DetailView<'a>>),
UserCommand(Box<UserCommandView<'a>>),
Refs(Box<RefsView<'a>>),
Help(Box<HelpView<'a>>),
}
impl<'a> View<'a> {
pub fn handle_event(&mut self, event_with_count: UserEventWithCount, key_event: KeyEvent) {
match self {
View::Default => {}
View::List(view) => view.handle_event(event_with_count, key_event),
View::Detail(view) => view.handle_event(event_with_count, key_event),
View::UserCommand(view) => view.handle_event(event_with_count, key_event),
View::Refs(view) => view.handle_event(event_with_count, key_event),
View::Help(view) => view.handle_event(event_with_count, key_event),
}
}
pub fn render(&mut self, f: &mut Frame, area: Rect) {
match self {
View::Default => {}
View::List(view) => view.render(f, area),
View::Detail(view) => view.render(f, area),
View::UserCommand(view) => view.render(f, area),
View::Refs(view) => view.render(f, area),
View::Help(view) => view.render(f, area),
}
}
pub fn of_list(
commit_list_state: CommitListState<'a>,
ctx: Rc<AppContext>,
tx: Sender,
) -> Self {
View::List(Box::new(ListView::new(commit_list_state, ctx, tx)))
}
pub fn of_detail(
commit_list_state: CommitListState<'a>,
commit: Commit,
changes: Vec<FileChange>,
refs: Vec<Ref>,
ctx: Rc<AppContext>,
tx: Sender,
) -> Self {
View::Detail(Box::new(DetailView::new(
commit_list_state,
commit,
changes,
refs,
ctx,
tx,
)))
}
pub fn of_user_command(
commit_list_state: CommitListState<'a>,
command_output: String,
user_command_number: usize,
ctx: Rc<AppContext>,
tx: Sender,
) -> Self {
View::UserCommand(Box::new(UserCommandView::new(
commit_list_state,
command_output,
user_command_number,
ctx,
tx,
)))
}
pub fn of_refs(
commit_list_state: CommitListState<'a>,
refs: Vec<Ref>,
ctx: Rc<AppContext>,
tx: Sender,
) -> Self {
View::Refs(Box::new(RefsView::new(commit_list_state, refs, ctx, tx)))
}
pub fn of_help(before: View<'a>, ctx: Rc<AppContext>, tx: Sender) -> Self {
View::Help(Box::new(HelpView::new(before, ctx, tx)))
}
pub fn refresh(&mut self) {
match self {
View::Default => {}
View::List(view) => view.refresh(),
View::Detail(view) => view.refresh(),
View::UserCommand(view) => view.refresh(),
View::Refs(view) => view.refresh(),
View::Help(_) => {}
}
}
}
#[derive(Debug, Clone)]
pub enum RefreshViewContext {
List {
list_context: ListRefreshViewContext,
},
Detail {
list_context: ListRefreshViewContext,
},
UserCommand {
list_context: ListRefreshViewContext,
user_command_context: UserCommandRefreshViewContext,
},
Refs {
list_context: ListRefreshViewContext,
refs_context: RefsRefreshViewContext,
},
}
impl RefreshViewContext {
pub fn list_context(&self) -> &ListRefreshViewContext {
match self {
RefreshViewContext::List { list_context }
| RefreshViewContext::Detail { list_context }
| RefreshViewContext::UserCommand { list_context, .. }
| RefreshViewContext::Refs { list_context, .. } => list_context,
}
}
}
#[derive(Debug, Clone)]
pub struct ListRefreshViewContext {
pub commit_hash: String,
pub selected: usize,
pub height: usize,
pub scroll_to_top: bool,
}
impl From<&CommitListState<'_>> for ListRefreshViewContext {
fn from(list_state: &CommitListState) -> Self {
let commit_hash = list_state.selected_commit_hash().as_str().into();
let (selected, offset, height) = list_state.current_list_status();
let scroll_to_top = selected == 0 && offset == 0;
ListRefreshViewContext {
commit_hash,
selected,
height,
scroll_to_top,
}
}
}
#[derive(Debug, Clone)]
pub struct UserCommandRefreshViewContext {
pub n: usize,
}
#[derive(Debug, Clone)]
pub struct RefsRefreshViewContext {
pub selected: Vec<String>,
pub opened: Vec<Vec<String>>,
}