From 829bb494c75ba0e4671fecf16fa3e88de0f577a1 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Mon, 12 Aug 2024 14:47:13 +0200 Subject: [PATCH] bin: Use generic browser state in `issue select` --- bin/commands/issue/select.rs | 103 +++++--------------------------- bin/commands/issue/select/ui.rs | 12 ++-- 2 files changed, 20 insertions(+), 95 deletions(-) diff --git a/bin/commands/issue/select.rs b/bin/commands/issue/select.rs index 66c75bb6..a64f27f3 100644 --- a/bin/commands/issue/select.rs +++ b/bin/commands/issue/select.rs @@ -36,8 +36,8 @@ use tui::{BoxedAny, Channel, Exit, PageStack}; use crate::cob::issue; use crate::settings::{self, ThemeBundle, ThemeMode}; -use crate::ui::items::{CommentItem, Filter, IssueItem, IssueItemFilter}; -use crate::ui::widget::{IssueDetails, IssueDetailsProps}; +use crate::ui::items::{CommentItem, IssueItem, IssueItemFilter}; +use crate::ui::widget::{BrowserState, IssueDetails, IssueDetailsProps}; use crate::ui::TerminalInfo; use self::ui::{Browser, BrowserProps}; @@ -95,74 +95,6 @@ impl From
for usize { } } -#[derive(Clone, Debug)] -pub struct BrowserState { - items: Vec, - selected: Option, - filter: IssueItemFilter, - search: store::StateValue, - show_search: bool, -} - -impl BrowserState { - pub fn issues(&self) -> Vec { - self.issues_ref().into_iter().cloned().collect() - } - - pub fn issues_ref(&self) -> Vec<&IssueItem> { - self.items - .iter() - .filter(|patch| self.filter.matches(patch)) - .collect() - } - - pub fn selected(&self) -> Option<&IssueItem> { - self.selected - .and_then(|selected| self.issues_ref().get(selected).copied()) - } - - pub fn select(&mut self, selected: Option) -> Option<&IssueItem> { - self.selected = selected; - self.selected() - } - - pub fn select_first(&mut self) -> Option<&IssueItem> { - self.selected.and_then(|selected| { - if selected > self.issues_ref().len() { - self.selected = Some(0); - self.issues_ref().first().cloned() - } else { - self.issues_ref().get(selected).cloned() - } - }) - } - - pub fn show_search(&mut self) { - self.show_search = true; - } - - pub fn hide_search(&mut self) { - self.show_search = false; - } - - pub fn apply_search(&mut self) { - self.search.apply(); - } - - pub fn reset_search(&mut self) { - self.search.reset(); - } - - pub fn search(&mut self, value: String) { - self.search.write(value); - self.filter_items(); - } - - pub fn filter_items(&mut self) { - self.filter = IssueItemFilter::from_str(&self.search.read()).unwrap_or_default(); - } -} - #[derive(Clone, Debug)] pub struct PreviewState { /// If preview is visible. @@ -227,7 +159,7 @@ pub struct HelpState { pub struct State { mode: Mode, pages: PageStack, - browser: BrowserState, + browser: BrowserState, preview: PreviewState, section: Option
, help: HelpState, @@ -283,13 +215,7 @@ impl TryFrom<(&Context, &TerminalInfo)> for State { Ok(Self { mode: context.mode.clone(), pages: PageStack::new(vec![AppPage::Browser]), - browser: BrowserState { - items: items.clone(), - selected: Some(0), - filter, - search, - show_search: false, - }, + browser: BrowserState::build(items.clone(), filter, search), preview: PreviewState { show: true, issue: items.first().cloned(), @@ -329,7 +255,7 @@ impl store::State for State { fn update(&mut self, message: Message) -> Option> { match message { Message::Quit => Some(Exit { value: None }), - Message::Exit { operation } => self.browser.selected().map(|issue| Exit { + Message::Exit { operation } => self.browser.selected_item().map(|issue| Exit { value: Some(Selection { operation: operation.map(|op| op.to_string()), ids: vec![issue.id], @@ -342,7 +268,7 @@ impl store::State for State { Mode::Id => None, }; - self.browser.selected().map(|issue| Exit { + self.browser.selected_item().map(|issue| Exit { value: Some(Selection { operation, ids: vec![issue.id], @@ -351,8 +277,8 @@ impl store::State for State { }) } Message::SelectIssue { selected } => { - self.browser.select(selected); - self.preview.issue = self.browser.selected().cloned(); + self.browser.select_item(selected); + self.preview.issue = self.browser.selected_item().cloned(); self.preview.comment.reset_cursor(); None } @@ -383,8 +309,8 @@ impl store::State for State { None } Message::UpdateSearch { value } => { - self.browser.search(value); - self.preview.issue = self.browser.select_first().cloned(); + self.browser.update_search(value); + self.preview.issue = self.browser.select_first_item().cloned(); None } Message::ApplySearch => { @@ -395,9 +321,8 @@ impl store::State for State { Message::CloseSearch => { self.browser.hide_search(); self.browser.reset_search(); - self.browser.filter_items(); - self.preview.issue = self.browser.selected().cloned(); + self.preview.issue = self.browser.selected_item().cloned(); self.preview.comment.reset_cursor(); None } @@ -451,7 +376,7 @@ fn browser_page(channel: &Channel) -> Widget { let shortcuts = Shortcuts::default() .to_widget(tx.clone()) .on_update(|state: &State| { - let shortcuts = if state.browser.show_search { + let shortcuts = if state.browser.is_search_shown() { vec![("esc", "cancel"), ("enter", "apply")] } else { let mut shortcuts = match state.mode { @@ -490,7 +415,7 @@ fn browser_page(channel: &Channel) -> Widget { }) .on_update(|state: &State| { SectionGroupProps::default() - .handle_keys(state.preview.show && !state.browser.show_search) + .handle_keys(state.preview.show && !state.browser.is_search_shown()) .layout(PredefinedLayout::Expandable3 { left_only: !state.preview.show, }) @@ -524,7 +449,7 @@ fn browser_page(channel: &Channel) -> Widget { }) .on_update(|state: &State| { PageProps::default() - .handle_keys(!state.browser.show_search) + .handle_keys(!state.browser.is_search_shown()) .to_boxed_any() .into() }) diff --git a/bin/commands/issue/select/ui.rs b/bin/commands/issue/select/ui.rs index 745bcd9c..8ae62683 100644 --- a/bin/commands/issue/select/ui.rs +++ b/bin/commands/issue/select/ui.rs @@ -52,7 +52,7 @@ impl<'a> From<&State> for BrowserProps<'a> { fn from(state: &State) -> Self { use radicle::issue::State; - let issues = state.browser.issues(); + let issues = state.browser.items(); let mut open = 0; let mut other = 0; @@ -104,8 +104,8 @@ impl<'a> From<&State> for BrowserProps<'a> { Column::new("Opened", Constraint::Length(16)).hide_small(), ] .to_vec(), - search: state.browser.search.read(), - show_search: state.browser.show_search, + search: state.browser.read_search(), + show_search: state.browser.is_search_shown(), } } } @@ -147,8 +147,8 @@ impl Browser { TableProps::default() .columns(props.columns) - .items(state.browser.issues()) - .selected(state.browser.selected) + .items(state.browser.items()) + .selected(state.browser.selected()) .dim(state.theme.dim_no_focus) .to_boxed_any() .into() @@ -182,7 +182,7 @@ impl Browser { }) .on_update(|state: &State| { TextFieldProps::default() - .text(&state.browser.search.read().to_string()) + .text(&state.browser.read_search()) .title("Search") .inline(true) .to_boxed_any()