diff --git a/src/components/inspector.rs b/src/components/inspector.rs index 7ac458f..577a7d3 100644 --- a/src/components/inspector.rs +++ b/src/components/inspector.rs @@ -21,18 +21,11 @@ use super::Component; pub struct InspectorComponent { action_tx: Option>, - state: TreeState, - - finished_first_render: bool, } impl<'a> InspectorComponent { pub fn new() -> Self { - Self { - action_tx: None, - state: TreeState::new(), - finished_first_render: false, - } + Self { action_tx: None } } fn item_builder(item: &DiagnosticNode) -> Node<'a> { @@ -61,7 +54,10 @@ impl<'a> InspectorComponent { return; }; let root = Self::item_builder(summary_tree); - let items = Tree::make_lines(&root, &self.state, &vec![], &vec![]); + let state = TreeState::new() + .with_opened(session.opened_widget_value_ids.clone()) + .with_selected(session.selected_widget_value_id.clone()); + let items = Tree::make_lines(&root, &state, &vec![], &vec![]); let current_index = items.iter().position(|(id, _)| { if let Some(selected) = session.selected_widget_value_id.as_ref() { @@ -105,7 +101,10 @@ impl<'a> InspectorComponent { return; }; let root = Self::item_builder(summary_tree); - let items = Tree::make_lines(&root, &self.state, &vec![], &vec![]); + let state = TreeState::new() + .with_opened(session.opened_widget_value_ids.clone()) + .with_selected(session.selected_widget_value_id.clone()); + let items = Tree::make_lines(&root, &state, &vec![], &vec![]); let current_index = items.iter().position(|(id, _)| { if let Some(selected) = session.selected_widget_value_id.as_ref() { @@ -147,18 +146,17 @@ impl<'a> InspectorComponent { let Some(selected_widget_id) = session.selected_widget_value_id.as_ref() else { return; }; - self.state.toggle(selected_widget_id); - } - - fn all_ids(node: &DiagnosticNode) -> HashSet { - let mut ids = HashSet::new(); - ids.insert(node.value_id.clone().unwrap_or_default()); - if let Some(children) = node.children.as_ref() { - for child in children { - ids.extend(Self::all_ids(child)); - } - } - ids + self.action_tx + .as_ref() + .unwrap() + .send( + Action::ToggleOpenWidgetValueId { + session_id: session.id.clone(), + id: selected_widget_id.clone(), + } + .into(), + ) + .unwrap(); } } @@ -202,12 +200,6 @@ impl Component for InspectorComponent { return; }; - if !self.finished_first_render { - self.finished_first_render = true; - let ids = Self::all_ids(summary_tree); - self.state.open_all(ids); - } - let root = Self::item_builder(summary_tree); let tree = Tree::new(root).block(block).highlight_style( if state.focus == Focus::DevTools(DevTools::Inspector) { @@ -217,10 +209,13 @@ impl Component for InspectorComponent { }, ); + let mut state = TreeState::new() + .with_opened(session.opened_widget_value_ids.clone()) + .with_selected(session.selected_widget_value_id.clone()); if let Some(selected_widget_value_id) = session.selected_widget_value_id.as_ref() { - *self.state.selected_mut() = Some(selected_widget_value_id.clone()); + *state.selected_mut() = Some(selected_widget_value_id.clone()); } - f.render_stateful_widget(tree, area, &mut self.state); + f.render_stateful_widget(tree, area, &mut state); } } diff --git a/src/redux/action.rs b/src/redux/action.rs index cd520ae..0b3cc86 100644 --- a/src/redux/action.rs +++ b/src/redux/action.rs @@ -4,7 +4,7 @@ use devtools::protocols::{ flutter_extension::DiagnosticNode, io_extension::{HttpProfileRequest, HttpProfileRequestRef}, }; -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::time::Duration; #[derive(Debug)] @@ -157,6 +157,16 @@ pub enum Action { id: String, }, + SetOpenWidgetValueId { + session_id: String, + ids: HashSet, + }, + + ToggleOpenWidgetValueId { + session_id: String, + id: String, + }, + NextLog, PreviousLog, diff --git a/src/redux/reducer.rs b/src/redux/reducer.rs index 46b8cc3..7efda21 100644 --- a/src/redux/reducer.rs +++ b/src/redux/reducer.rs @@ -1004,6 +1004,7 @@ pub fn reducer(state: State, action: Action) -> State { if s.id == session_id { SessionState { widget_summary_tree: Some(tree.clone()), + selected_widget_value_id: tree.value_id.clone(), ..s } } else { @@ -1030,5 +1031,45 @@ pub fn reducer(state: State, action: Action) -> State { .collect(), ..state }, + Action::SetOpenWidgetValueId { session_id, ids } => State { + sessions: state + .sessions + .into_iter() + .map(|s| { + if s.id == session_id { + SessionState { + opened_widget_value_ids: ids.clone(), + ..s + } + } else { + s + } + }) + .collect(), + ..state + }, + Action::ToggleOpenWidgetValueId { session_id, id } => State { + sessions: state + .sessions + .into_iter() + .map(|s| { + if s.id == session_id { + let mut opened_widget_value_ids = s.opened_widget_value_ids.clone(); + if opened_widget_value_ids.contains(&id) { + opened_widget_value_ids.remove(&id); + } else { + opened_widget_value_ids.insert(id.clone()); + } + SessionState { + opened_widget_value_ids, + ..s + } + } else { + s + } + }) + .collect(), + ..state + }, } } diff --git a/src/redux/state.rs b/src/redux/state.rs index cabbc26..77fe3a6 100644 --- a/src/redux/state.rs +++ b/src/redux/state.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::path::PathBuf; use std::time::Duration; use std::{collections::HashMap, time::SystemTime}; @@ -109,6 +110,7 @@ pub struct SessionState { pub display_refresh_rate: f32, pub widget_summary_tree: Option, pub selected_widget_value_id: Option, + pub opened_widget_value_ids: HashSet, } #[derive(Default, Clone, PartialEq, Eq)] diff --git a/src/redux/thunk/load_root_widget_summary_tree.rs b/src/redux/thunk/load_root_widget_summary_tree.rs index 3fd50a8..5d0b893 100644 --- a/src/redux/thunk/load_root_widget_summary_tree.rs +++ b/src/redux/thunk/load_root_widget_summary_tree.rs @@ -1,6 +1,10 @@ use async_trait::async_trait; use color_eyre::eyre::Result; -use std::{collections::HashMap, sync::Arc, time::Duration}; +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, + time::Duration, +}; use tokio::time::sleep; use redux_rs::{middlewares::thunk::Thunk, StoreApi}; @@ -13,7 +17,7 @@ use crate::redux::{ use devtools::{ protocols::{ - flutter_extension::FlutterExtensionProtocol, + flutter_extension::{DiagnosticNode, FlutterExtensionProtocol}, io_extension::IoExtensionProtocol, vm_service::{EventKind, StreamId, VmServiceProtocol}, }, @@ -36,6 +40,17 @@ impl LoadRootWidgetWithSummaryTreeThunk { session_id, } } + + fn all_ids(node: &DiagnosticNode) -> HashSet { + let mut ids = HashSet::new(); + ids.insert(node.value_id.clone().unwrap_or_default()); + if let Some(children) = node.children.as_ref() { + for child in children { + ids.extend(Self::all_ids(child)); + } + } + ids + } } #[async_trait] @@ -77,6 +92,13 @@ where } }; + store + .dispatch(Action::SetOpenWidgetValueId { + session_id: self.session_id.clone(), + ids: Self::all_ids(&response.result), + }) + .await; + store .dispatch(Action::SetWidgetSummaryTree { session_id: self.session_id.clone(),