Replaced all list uses with the SelectableList widget and popup widget. Simplified more popups to use the widgets
This commit is contained in:
+3
-74
@@ -3,25 +3,23 @@ use std::iter;
|
|||||||
use ratatui::layout::{Alignment, Constraint, Flex, Layout, Rect};
|
use ratatui::layout::{Alignment, Constraint, Flex, Layout, Rect};
|
||||||
use ratatui::style::{Style, Stylize};
|
use ratatui::style::{Style, Stylize};
|
||||||
use ratatui::text::{Line, Text};
|
use ratatui::text::{Line, Text};
|
||||||
|
use ratatui::widgets::Clear;
|
||||||
use ratatui::widgets::Paragraph;
|
use ratatui::widgets::Paragraph;
|
||||||
use ratatui::widgets::Tabs;
|
use ratatui::widgets::Tabs;
|
||||||
use ratatui::widgets::Wrap;
|
use ratatui::widgets::Wrap;
|
||||||
use ratatui::widgets::{Clear, List, ListItem};
|
|
||||||
use ratatui::Frame;
|
use ratatui::Frame;
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::models::stateful_list::StatefulList;
|
|
||||||
use crate::models::{HorizontallyScrollableText, Route, TabState};
|
use crate::models::{HorizontallyScrollableText, Route, TabState};
|
||||||
use crate::ui::radarr_ui::RadarrUi;
|
use crate::ui::radarr_ui::RadarrUi;
|
||||||
use crate::ui::styles::ManagarrStyle;
|
use crate::ui::styles::ManagarrStyle;
|
||||||
use crate::ui::utils::{
|
use crate::ui::utils::{
|
||||||
background_block, borderless_block, centered_rect, layout_block_top_border,
|
background_block, borderless_block, centered_rect, layout_paragraph_borderless, logo_block,
|
||||||
layout_paragraph_borderless, logo_block, title_block, title_block_centered,
|
title_block, title_block_centered,
|
||||||
};
|
};
|
||||||
use crate::ui::widgets::button::Button;
|
use crate::ui::widgets::button::Button;
|
||||||
use crate::ui::widgets::checkbox::Checkbox;
|
use crate::ui::widgets::checkbox::Checkbox;
|
||||||
use crate::ui::widgets::input_box::InputBox;
|
use crate::ui::widgets::input_box::InputBox;
|
||||||
use crate::ui::widgets::loading_block::LoadingBlock;
|
|
||||||
|
|
||||||
mod radarr_ui;
|
mod radarr_ui;
|
||||||
mod styles;
|
mod styles;
|
||||||
@@ -238,14 +236,6 @@ fn draw_tabs(f: &mut Frame<'_>, area: Rect, title: &str, tab_state: &TabState) -
|
|||||||
content_area
|
content_area
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ListProps<'a, T> {
|
|
||||||
pub content: &'a mut StatefulList<T>,
|
|
||||||
pub title: &'static str,
|
|
||||||
pub is_loading: bool,
|
|
||||||
pub is_popup: bool,
|
|
||||||
pub help: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw_prompt_box(
|
pub fn draw_prompt_box(
|
||||||
f: &mut Frame<'_>,
|
f: &mut Frame<'_>,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
@@ -351,67 +341,6 @@ pub fn draw_prompt_box_with_checkboxes(
|
|||||||
f.render_widget(no_button, no_area);
|
f.render_widget(no_button, no_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_list_box<'a, T>(
|
|
||||||
f: &mut Frame<'_>,
|
|
||||||
area: Rect,
|
|
||||||
item_mapper: impl Fn(&T) -> ListItem<'a>,
|
|
||||||
list_props: ListProps<'a, T>,
|
|
||||||
) {
|
|
||||||
let ListProps {
|
|
||||||
content,
|
|
||||||
title,
|
|
||||||
is_loading,
|
|
||||||
is_popup,
|
|
||||||
help,
|
|
||||||
} = list_props;
|
|
||||||
|
|
||||||
let (content_area, block) = if is_popup {
|
|
||||||
f.render_widget(title_block(title), area);
|
|
||||||
(
|
|
||||||
draw_help_footer_and_get_content_area(f, area, help),
|
|
||||||
borderless_block(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(area, title_block(title))
|
|
||||||
};
|
|
||||||
|
|
||||||
if !content.items.is_empty() {
|
|
||||||
let items: Vec<ListItem<'_>> = content.items.iter().map(item_mapper).collect();
|
|
||||||
let mut list = List::new(items).block(block);
|
|
||||||
|
|
||||||
if is_popup {
|
|
||||||
list = list.highlight_style(Style::new().highlight());
|
|
||||||
}
|
|
||||||
|
|
||||||
f.render_stateful_widget(list, content_area, &mut content.state);
|
|
||||||
} else {
|
|
||||||
f.render_widget(LoadingBlock::new(is_loading, block), content_area);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_help_footer_and_get_content_area(
|
|
||||||
f: &mut Frame<'_>,
|
|
||||||
area: Rect,
|
|
||||||
help: Option<String>,
|
|
||||||
) -> Rect {
|
|
||||||
if let Some(help_string) = help {
|
|
||||||
let [content_area, help_footer_area] =
|
|
||||||
Layout::vertical([Constraint::Fill(0), Constraint::Length(2)])
|
|
||||||
.margin(1)
|
|
||||||
.areas(area);
|
|
||||||
|
|
||||||
let help_paragraph = Paragraph::new(Text::from(format!(" {help_string}").help()))
|
|
||||||
.block(layout_block_top_border())
|
|
||||||
.alignment(Alignment::Left);
|
|
||||||
|
|
||||||
f.render_widget(help_paragraph, help_footer_area);
|
|
||||||
|
|
||||||
content_area
|
|
||||||
} else {
|
|
||||||
area
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw_input_box_popup(
|
pub fn draw_input_box_popup(
|
||||||
f: &mut Frame<'_>,
|
f: &mut Frame<'_>,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::ops::Sub;
|
|||||||
|
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use ratatui::layout::{Alignment, Layout};
|
use ratatui::layout::{Alignment, Layout};
|
||||||
|
use ratatui::style::Style;
|
||||||
use ratatui::text::{Span, Text};
|
use ratatui::text::{Span, Text};
|
||||||
use ratatui::widgets::{Cell, Paragraph, Row};
|
use ratatui::widgets::{Cell, Paragraph, Row};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
@@ -17,11 +18,12 @@ use crate::ui::radarr_ui::radarr_ui_utils::{convert_to_minutes_hours_days, style
|
|||||||
use crate::ui::radarr_ui::system::system_details_ui::SystemDetailsUi;
|
use crate::ui::radarr_ui::system::system_details_ui::SystemDetailsUi;
|
||||||
use crate::ui::styles::ManagarrStyle;
|
use crate::ui::styles::ManagarrStyle;
|
||||||
use crate::ui::utils::layout_block_top_border;
|
use crate::ui::utils::layout_block_top_border;
|
||||||
|
use crate::ui::widgets::loading_block::LoadingBlock;
|
||||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||||
use crate::ui::ListProps;
|
use crate::ui::widgets::selectable_list::SelectableList;
|
||||||
use crate::{
|
use crate::{
|
||||||
models::Route,
|
models::Route,
|
||||||
ui::{draw_list_box, utils::title_block, DrawUi},
|
ui::{utils::title_block, DrawUi},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod system_details_ui;
|
mod system_details_ui;
|
||||||
@@ -168,23 +170,23 @@ pub(super) fn draw_queued_events(f: &mut Frame<'_>, app: &mut App<'_>, area: Rec
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw_logs(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
fn draw_logs(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||||
draw_list_box(
|
let block = title_block("Logs");
|
||||||
f,
|
|
||||||
area,
|
|
||||||
|log| {
|
|
||||||
let log_line = log.to_string();
|
|
||||||
let level = log_line.split('|').collect::<Vec<&str>>()[1].to_string();
|
|
||||||
|
|
||||||
style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level)
|
if app.data.radarr_data.logs.items.is_empty() {
|
||||||
},
|
f.render_widget(LoadingBlock::new(app.is_loading, block), area);
|
||||||
ListProps {
|
return;
|
||||||
content: &mut app.data.radarr_data.logs,
|
}
|
||||||
title: "Logs",
|
|
||||||
is_loading: app.is_loading,
|
let logs_box = SelectableList::new(&mut app.data.radarr_data.logs, |log| {
|
||||||
is_popup: false,
|
let log_line = log.to_string();
|
||||||
help: None,
|
let level = log_line.split('|').collect::<Vec<&str>>()[1].to_string();
|
||||||
},
|
|
||||||
);
|
style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level)
|
||||||
|
})
|
||||||
|
.block(block)
|
||||||
|
.highlight_style(Style::new().default());
|
||||||
|
|
||||||
|
f.render_widget(logs_box, area);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_help(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
fn draw_help(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ use crate::ui::styles::ManagarrStyle;
|
|||||||
use crate::ui::utils::{borderless_block, title_block};
|
use crate::ui::utils::{borderless_block, title_block};
|
||||||
use crate::ui::widgets::loading_block::LoadingBlock;
|
use crate::ui::widgets::loading_block::LoadingBlock;
|
||||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||||
|
use crate::ui::widgets::popup::Popup;
|
||||||
|
use crate::ui::widgets::selectable_list::SelectableList;
|
||||||
use crate::ui::{
|
use crate::ui::{
|
||||||
draw_help_footer_and_get_content_area, draw_large_popup_over, draw_list_box,
|
draw_large_popup_over, draw_medium_popup_over, draw_prompt_box, draw_prompt_popup_over, DrawUi,
|
||||||
draw_medium_popup_over, draw_prompt_box, draw_prompt_popup_over, DrawUi, ListProps,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -42,7 +43,8 @@ impl DrawUi for SystemDetailsUi {
|
|||||||
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
|
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
|
||||||
match active_radarr_block {
|
match active_radarr_block {
|
||||||
ActiveRadarrBlock::SystemLogs => {
|
ActiveRadarrBlock::SystemLogs => {
|
||||||
draw_large_popup_over(f, app, area, draw_system_ui_layout, draw_logs_popup)
|
draw_system_ui_layout(f, app, area);
|
||||||
|
draw_logs_popup(f, app);
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::SystemTasks | ActiveRadarrBlock::SystemTaskStartConfirmPrompt => {
|
ActiveRadarrBlock::SystemTasks | ActiveRadarrBlock::SystemTaskStartConfirmPrompt => {
|
||||||
draw_large_popup_over(f, app, area, draw_system_ui_layout, draw_tasks_popup)
|
draw_large_popup_over(f, app, area, draw_system_ui_layout, draw_tasks_popup)
|
||||||
@@ -51,7 +53,8 @@ impl DrawUi for SystemDetailsUi {
|
|||||||
draw_medium_popup_over(f, app, area, draw_system_ui_layout, draw_queued_events)
|
draw_medium_popup_over(f, app, area, draw_system_ui_layout, draw_queued_events)
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::SystemUpdates => {
|
ActiveRadarrBlock::SystemUpdates => {
|
||||||
draw_large_popup_over(f, app, area, draw_system_ui_layout, draw_updates_popup)
|
draw_system_ui_layout(f, app, area);
|
||||||
|
draw_updates_popup(f, app);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@@ -59,27 +62,35 @@ impl DrawUi for SystemDetailsUi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_logs_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
fn draw_logs_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
|
||||||
draw_list_box(
|
let block = title_block("Log Details");
|
||||||
f,
|
let help_footer = format!(
|
||||||
area,
|
"<↑↓←→> scroll | {}",
|
||||||
|log| {
|
build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES)
|
||||||
let log_line = log.to_string();
|
|
||||||
let level = log.text.split('|').collect::<Vec<&str>>()[1].to_string();
|
|
||||||
|
|
||||||
style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level)
|
|
||||||
},
|
|
||||||
ListProps {
|
|
||||||
content: &mut app.data.radarr_data.log_details,
|
|
||||||
title: "Log Details",
|
|
||||||
is_loading: app.is_loading,
|
|
||||||
is_popup: true,
|
|
||||||
help: Some(format!(
|
|
||||||
"<↑↓←→> scroll | {}",
|
|
||||||
build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES)
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if app.data.radarr_data.log_details.items.is_empty() {
|
||||||
|
let loading = LoadingBlock::new(app.is_loading, borderless_block());
|
||||||
|
let popup = Popup::new(loading, 75, 75)
|
||||||
|
.block(block)
|
||||||
|
.footer(&help_footer);
|
||||||
|
|
||||||
|
f.render_widget(popup, f.size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let logs_list = SelectableList::new(&mut app.data.radarr_data.log_details, |log| {
|
||||||
|
let log_line = log.to_string();
|
||||||
|
let level = log.text.split('|').collect::<Vec<&str>>()[1].to_string();
|
||||||
|
|
||||||
|
style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level)
|
||||||
|
})
|
||||||
|
.block(borderless_block());
|
||||||
|
let popup = Popup::new(logs_list, 75, 75)
|
||||||
|
.block(block)
|
||||||
|
.footer(&help_footer);
|
||||||
|
|
||||||
|
f.render_widget(popup, f.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_tasks_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
fn draw_tasks_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||||
@@ -134,27 +145,29 @@ fn draw_start_task_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_updates_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
fn draw_updates_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
|
||||||
f.render_widget(title_block("Updates"), area);
|
let help_footer = format!(
|
||||||
|
"<↑↓> scroll | {}",
|
||||||
let content_area = draw_help_footer_and_get_content_area(
|
build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES)
|
||||||
f,
|
|
||||||
area,
|
|
||||||
Some(format!(
|
|
||||||
"<↑↓> scroll | {}",
|
|
||||||
build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES)
|
|
||||||
)),
|
|
||||||
);
|
);
|
||||||
let updates = app.data.radarr_data.updates.get_text();
|
let updates = app.data.radarr_data.updates.get_text();
|
||||||
let block = borderless_block();
|
let block = title_block("Updates");
|
||||||
|
|
||||||
if !updates.is_empty() {
|
if !updates.is_empty() {
|
||||||
let updates_paragraph = Paragraph::new(Text::from(updates))
|
let updates_paragraph = Paragraph::new(Text::from(updates))
|
||||||
.block(block)
|
.block(borderless_block())
|
||||||
.scroll((app.data.radarr_data.updates.offset, 0));
|
.scroll((app.data.radarr_data.updates.offset, 0));
|
||||||
|
let popup = Popup::new(updates_paragraph, 75, 75)
|
||||||
|
.block(block)
|
||||||
|
.footer(&help_footer);
|
||||||
|
|
||||||
f.render_widget(updates_paragraph, content_area);
|
f.render_widget(popup, f.size());
|
||||||
} else {
|
} else {
|
||||||
f.render_widget(LoadingBlock::new(app.is_loading, block), content_area);
|
let loading = LoadingBlock::new(app.is_loading, borderless_block());
|
||||||
|
let popup = Popup::new(loading, 75, 75)
|
||||||
|
.block(block)
|
||||||
|
.footer(&help_footer);
|
||||||
|
|
||||||
|
f.render_widget(popup, f.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-8
@@ -1,37 +1,80 @@
|
|||||||
use crate::ui::utils::{background_block, centered_rect};
|
use crate::ui::styles::ManagarrStyle;
|
||||||
|
use crate::ui::utils::{background_block, centered_rect, layout_block_top_border};
|
||||||
use ratatui::buffer::Buffer;
|
use ratatui::buffer::Buffer;
|
||||||
use ratatui::layout::Rect;
|
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||||
use ratatui::widgets::{Clear, Widget};
|
use ratatui::prelude::Text;
|
||||||
|
use ratatui::widgets::{Block, Clear, Paragraph, Widget};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "popup_tests.rs"]
|
#[path = "popup_tests.rs"]
|
||||||
mod popup_tests;
|
mod popup_tests;
|
||||||
|
|
||||||
pub struct Popup<T: Widget> {
|
pub struct Popup<'a, T: Widget> {
|
||||||
widget: T,
|
widget: T,
|
||||||
percent_x: u16,
|
percent_x: u16,
|
||||||
percent_y: u16,
|
percent_y: u16,
|
||||||
|
block: Option<Block<'a>>,
|
||||||
|
footer: Option<&'a str>,
|
||||||
|
footer_alignment: Alignment,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Widget> Popup<T> {
|
impl<'a, T: Widget> Popup<'a, T> {
|
||||||
pub fn new(widget: T, percent_x: u16, percent_y: u16) -> Self {
|
pub fn new(widget: T, percent_x: u16, percent_y: u16) -> Self {
|
||||||
Self {
|
Self {
|
||||||
widget,
|
widget,
|
||||||
percent_x,
|
percent_x,
|
||||||
percent_y,
|
percent_y,
|
||||||
|
block: None,
|
||||||
|
footer: None,
|
||||||
|
footer_alignment: Alignment::Left,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn block(mut self, block: Block<'a>) -> Self {
|
||||||
|
self.block = Some(block);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn footer(mut self, footer: &'a str) -> Self {
|
||||||
|
self.footer = Some(footer);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn footer_alignment(mut self, alignment: Alignment) -> Self {
|
||||||
|
self.footer_alignment = alignment;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn render_popup(self, area: Rect, buf: &mut Buffer) {
|
fn render_popup(self, area: Rect, buf: &mut Buffer) {
|
||||||
let popup_area = centered_rect(self.percent_x, self.percent_y, area);
|
let popup_area = centered_rect(self.percent_x, self.percent_y, area);
|
||||||
|
|
||||||
Clear.render(popup_area, buf);
|
Clear.render(popup_area, buf);
|
||||||
background_block().render(popup_area, buf);
|
background_block().render(popup_area, buf);
|
||||||
self.widget.render(popup_area, buf);
|
|
||||||
|
if let Some(block) = self.block {
|
||||||
|
block.render(popup_area, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
let content_area = if let Some(footer) = self.footer {
|
||||||
|
let [content_area, help_footer_area] =
|
||||||
|
Layout::vertical([Constraint::Fill(0), Constraint::Length(2)])
|
||||||
|
.margin(1)
|
||||||
|
.areas(popup_area);
|
||||||
|
|
||||||
|
Paragraph::new(Text::from(format!(" {footer}").help()))
|
||||||
|
.block(layout_block_top_border())
|
||||||
|
.alignment(self.footer_alignment)
|
||||||
|
.render(help_footer_area, buf);
|
||||||
|
|
||||||
|
content_area
|
||||||
|
} else {
|
||||||
|
popup_area
|
||||||
|
};
|
||||||
|
|
||||||
|
self.widget.render(content_area, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Widget> Widget for Popup<T> {
|
impl<'a, T: Widget> Widget for Popup<'a, T> {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
self.render_popup(area, buf);
|
self.render_popup(area, buf);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
mod tests {
|
mod tests {
|
||||||
use crate::ui::widgets::popup::Popup;
|
use crate::ui::widgets::popup::Popup;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
use ratatui::layout::Alignment;
|
||||||
use ratatui::widgets::Block;
|
use ratatui::widgets::Block;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -11,5 +12,44 @@ mod tests {
|
|||||||
assert_eq!(popup.widget, Block::new());
|
assert_eq!(popup.widget, Block::new());
|
||||||
assert_eq!(popup.percent_x, 50);
|
assert_eq!(popup.percent_x, 50);
|
||||||
assert_eq!(popup.percent_y, 50);
|
assert_eq!(popup.percent_y, 50);
|
||||||
|
assert_eq!(popup.block, None);
|
||||||
|
assert_eq!(popup.footer, None);
|
||||||
|
assert_eq!(popup.footer_alignment, Alignment::Left);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_popup_block() {
|
||||||
|
let popup = Popup::new(Block::new(), 50, 50).block(Block::new());
|
||||||
|
|
||||||
|
assert_eq!(popup.block, Some(Block::new()));
|
||||||
|
assert_eq!(popup.widget, Block::new());
|
||||||
|
assert_eq!(popup.percent_x, 50);
|
||||||
|
assert_eq!(popup.percent_y, 50);
|
||||||
|
assert_eq!(popup.footer, None);
|
||||||
|
assert_eq!(popup.footer_alignment, Alignment::Left);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_popup_footer() {
|
||||||
|
let popup = Popup::new(Block::new(), 50, 50).footer("footer");
|
||||||
|
|
||||||
|
assert_eq!(popup.footer, Some("footer"));
|
||||||
|
assert_eq!(popup.widget, Block::new());
|
||||||
|
assert_eq!(popup.percent_x, 50);
|
||||||
|
assert_eq!(popup.percent_y, 50);
|
||||||
|
assert_eq!(popup.block, None);
|
||||||
|
assert_eq!(popup.footer_alignment, Alignment::Left);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_popup_footer_alignment() {
|
||||||
|
let popup = Popup::new(Block::new(), 50, 50).footer_alignment(Alignment::Center);
|
||||||
|
|
||||||
|
assert_eq!(popup.footer_alignment, Alignment::Center);
|
||||||
|
assert_eq!(popup.widget, Block::new());
|
||||||
|
assert_eq!(popup.percent_x, 50);
|
||||||
|
assert_eq!(popup.percent_y, 50);
|
||||||
|
assert_eq!(popup.block, None);
|
||||||
|
assert_eq!(popup.footer, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use ratatui::buffer::Buffer;
|
|||||||
use ratatui::layout::Rect;
|
use ratatui::layout::Rect;
|
||||||
use ratatui::prelude::Widget;
|
use ratatui::prelude::Widget;
|
||||||
use ratatui::style::Style;
|
use ratatui::style::Style;
|
||||||
use ratatui::widgets::{List, ListItem, StatefulWidget};
|
use ratatui::widgets::{Block, List, ListItem, StatefulWidget};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "selectable_list_tests.rs"]
|
#[path = "selectable_list_tests.rs"]
|
||||||
@@ -17,6 +17,8 @@ where
|
|||||||
{
|
{
|
||||||
content: &'a mut StatefulList<T>,
|
content: &'a mut StatefulList<T>,
|
||||||
row_mapper: F,
|
row_mapper: F,
|
||||||
|
highlight_style: Style,
|
||||||
|
block: Block<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, F> SelectableList<'a, T, F>
|
impl<'a, T, F> SelectableList<'a, T, F>
|
||||||
@@ -27,15 +29,27 @@ where
|
|||||||
Self {
|
Self {
|
||||||
content,
|
content,
|
||||||
row_mapper,
|
row_mapper,
|
||||||
|
highlight_style: Style::new().highlight(),
|
||||||
|
block: layout_block(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn highlight_style(mut self, style: Style) -> Self {
|
||||||
|
self.highlight_style = style;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block(mut self, block: Block<'a>) -> Self {
|
||||||
|
self.block = block;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn render_list(self, area: Rect, buf: &mut Buffer) {
|
fn render_list(self, area: Rect, buf: &mut Buffer) {
|
||||||
let items: Vec<ListItem<'_>> = self.content.items.iter().map(&self.row_mapper).collect();
|
let items: Vec<ListItem<'_>> = self.content.items.iter().map(&self.row_mapper).collect();
|
||||||
|
|
||||||
let selectable_list = List::new(items)
|
let selectable_list = List::new(items)
|
||||||
.block(layout_block())
|
.block(self.block)
|
||||||
.highlight_style(Style::new().highlight());
|
.highlight_style(self.highlight_style);
|
||||||
|
|
||||||
StatefulWidget::render(selectable_list, area, buf, &mut self.content.state);
|
StatefulWidget::render(selectable_list, area, buf, &mut self.content.state);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::models::stateful_list::StatefulList;
|
use crate::models::stateful_list::StatefulList;
|
||||||
|
use crate::ui::styles::ManagarrStyle;
|
||||||
|
use crate::ui::utils::{layout_block, title_block};
|
||||||
use crate::ui::widgets::selectable_list::SelectableList;
|
use crate::ui::widgets::selectable_list::SelectableList;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
use ratatui::style::{Style, Stylize};
|
||||||
use ratatui::widgets::ListItem;
|
use ratatui::widgets::ListItem;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -17,5 +20,41 @@ mod tests {
|
|||||||
let row_mapper = selectable_list.row_mapper;
|
let row_mapper = selectable_list.row_mapper;
|
||||||
assert_eq!(selectable_list.content.items, items);
|
assert_eq!(selectable_list.content.items, items);
|
||||||
assert_eq!(row_mapper(&"test"), ListItem::new("test"));
|
assert_eq!(row_mapper(&"test"), ListItem::new("test"));
|
||||||
|
assert_eq!(selectable_list.highlight_style, Style::new().highlight());
|
||||||
|
assert_eq!(selectable_list.block, layout_block());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_selectable_list_highlight_style() {
|
||||||
|
let items = vec!["test"];
|
||||||
|
let mut stateful_list = StatefulList::default();
|
||||||
|
stateful_list.set_items(items.clone());
|
||||||
|
|
||||||
|
let selectable_list =
|
||||||
|
SelectableList::new(&mut stateful_list, |item| ListItem::new(item.to_string()))
|
||||||
|
.highlight_style(Style::new().bold());
|
||||||
|
|
||||||
|
let row_mapper = selectable_list.row_mapper;
|
||||||
|
assert_eq!(selectable_list.highlight_style, Style::new().bold());
|
||||||
|
assert_eq!(selectable_list.content.items, items);
|
||||||
|
assert_eq!(row_mapper(&"test"), ListItem::new("test"));
|
||||||
|
assert_eq!(selectable_list.block, layout_block());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_selectable_list_block() {
|
||||||
|
let items = vec!["test"];
|
||||||
|
let mut stateful_list = StatefulList::default();
|
||||||
|
stateful_list.set_items(items.clone());
|
||||||
|
|
||||||
|
let selectable_list =
|
||||||
|
SelectableList::new(&mut stateful_list, |item| ListItem::new(item.to_string()))
|
||||||
|
.block(title_block("test"));
|
||||||
|
|
||||||
|
let row_mapper = selectable_list.row_mapper;
|
||||||
|
assert_eq!(selectable_list.block, title_block("test"));
|
||||||
|
assert_eq!(selectable_list.content.items, items);
|
||||||
|
assert_eq!(row_mapper(&"test"), ListItem::new("test"));
|
||||||
|
assert_eq!(selectable_list.highlight_style, Style::new().highlight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user