use std::sync::Arc; use crate::{ api, app, component::file_tree::{FileTreeState, file_tree}, query::{self, QueryStatus, read_query, use_query, watch_query}, screen::dashboard::pull_request_diff_view::PullRequestDiffView, util::{ self, file::{FileTreeItem, FileTreeItemKind}, }, }; use gpui::{AppContext, ParentElement, Styled, div}; pub(crate) struct PullRequestChangeView { selected_file_path: Option>, diff_view: gpui::Entity, file_tree_query: query::Entity, file_tree_state: FileTreeState, file_tree_items: Vec, } pub(crate) fn new( pr_id: api::issues::Id, cx: &mut gpui::Context, ) -> PullRequestChangeView { let mut view = PullRequestChangeView { selected_file_path: None, diff_view: cx.new(|cx| PullRequestDiffView::new(pr_id.clone(), cx)), file_tree_query: use_query( api::issues::FetchPullRequestFileTree { id: pr_id, first: 100, }, cx, ), file_tree_state: FileTreeState::new(), file_tree_items: Vec::new(), }; view.on_create(cx); view } impl PullRequestChangeView { fn on_create(&mut self, cx: &mut gpui::Context) { watch_query( &self.file_tree_query, |this, query, cx| { if let QueryStatus::Loaded(changed_files) = read_query(query, cx) { let tree = util::file::build_file_tree(changed_files, |f| &f.path); this.file_tree_state.reset(&tree); this.file_tree_items = tree; cx.notify(); }; }, cx, ) .detach(); } fn handle_file_tree_item_click( &mut self, i: usize, window: &mut gpui::Window, cx: &mut gpui::Context, ) { let item = &self.file_tree_items[i]; match item.kind { | FileTreeItemKind::Directory => { self.file_tree_state .toggle_directory(&item.full_path, &self.file_tree_items); cx.notify(); } | FileTreeItemKind::File => { self.selected_file_path = Some(Arc::clone(&item.full_path)); self.file_tree_state.highlight_item(i); self.diff_view.update(cx, |diff_view, cx| { diff_view.show_diff_for_file(&item.full_path, cx); }); cx.focus_view(&self.diff_view, window); cx.notify(); } } } } impl gpui::Render for PullRequestChangeView { fn render( &mut self, _window: &mut gpui::Window, cx: &mut gpui::Context, ) -> impl gpui::IntoElement { let theme = app::current_theme(cx); let weak = cx.entity(); div() .size_full() .flex() .flex_row() .child( div() .flex() .w_80() .h_full() .bg(theme.colors.surface_chrome) .border_r_1() .border_color(theme.colors.border_muted) .child( file_tree(self.file_tree_state.clone(), move |i, _, cx| { weak.read(cx).file_tree_items[i].clone() }) .on_item_click(cx.listener( |this, i, window, cx| { this.handle_file_tree_item_click(*i, window, cx); }, )), ), ) .child( gpui::AnyView::from(self.diff_view.clone()) .cached(gpui::StyleRefinement::default().size_full()), ) } }