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::style::{Style, Stylize};
|
||||
use ratatui::text::{Line, Text};
|
||||
use ratatui::widgets::Clear;
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::widgets::Tabs;
|
||||
use ratatui::widgets::Wrap;
|
||||
use ratatui::widgets::{Clear, List, ListItem};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::stateful_list::StatefulList;
|
||||
use crate::models::{HorizontallyScrollableText, Route, TabState};
|
||||
use crate::ui::radarr_ui::RadarrUi;
|
||||
use crate::ui::styles::ManagarrStyle;
|
||||
use crate::ui::utils::{
|
||||
background_block, borderless_block, centered_rect, layout_block_top_border,
|
||||
layout_paragraph_borderless, logo_block, title_block, title_block_centered,
|
||||
background_block, borderless_block, centered_rect, layout_paragraph_borderless, logo_block,
|
||||
title_block, title_block_centered,
|
||||
};
|
||||
use crate::ui::widgets::button::Button;
|
||||
use crate::ui::widgets::checkbox::Checkbox;
|
||||
use crate::ui::widgets::input_box::InputBox;
|
||||
use crate::ui::widgets::loading_block::LoadingBlock;
|
||||
|
||||
mod radarr_ui;
|
||||
mod styles;
|
||||
@@ -238,14 +236,6 @@ fn draw_tabs(f: &mut Frame<'_>, area: Rect, title: &str, tab_state: &TabState) -
|
||||
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(
|
||||
f: &mut Frame<'_>,
|
||||
area: Rect,
|
||||
@@ -351,67 +341,6 @@ pub fn draw_prompt_box_with_checkboxes(
|
||||
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(
|
||||
f: &mut Frame<'_>,
|
||||
area: Rect,
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::ops::Sub;
|
||||
|
||||
use chrono::Utc;
|
||||
use ratatui::layout::{Alignment, Layout};
|
||||
use ratatui::style::Style;
|
||||
use ratatui::text::{Span, Text};
|
||||
use ratatui::widgets::{Cell, Paragraph, Row};
|
||||
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::styles::ManagarrStyle;
|
||||
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::ListProps;
|
||||
use crate::ui::widgets::selectable_list::SelectableList;
|
||||
use crate::{
|
||||
models::Route,
|
||||
ui::{draw_list_box, utils::title_block, DrawUi},
|
||||
ui::{utils::title_block, DrawUi},
|
||||
};
|
||||
|
||||
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) {
|
||||
draw_list_box(
|
||||
f,
|
||||
area,
|
||||
|log| {
|
||||
let log_line = log.to_string();
|
||||
let level = log_line.split('|').collect::<Vec<&str>>()[1].to_string();
|
||||
let block = title_block("Logs");
|
||||
|
||||
style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level)
|
||||
},
|
||||
ListProps {
|
||||
content: &mut app.data.radarr_data.logs,
|
||||
title: "Logs",
|
||||
is_loading: app.is_loading,
|
||||
is_popup: false,
|
||||
help: None,
|
||||
},
|
||||
);
|
||||
if app.data.radarr_data.logs.items.is_empty() {
|
||||
f.render_widget(LoadingBlock::new(app.is_loading, block), area);
|
||||
return;
|
||||
}
|
||||
|
||||
let logs_box = SelectableList::new(&mut app.data.radarr_data.logs, |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)
|
||||
})
|
||||
.block(block)
|
||||
.highlight_style(Style::new().default());
|
||||
|
||||
f.render_widget(logs_box, area);
|
||||
}
|
||||
|
||||
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::widgets::loading_block::LoadingBlock;
|
||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||
use crate::ui::widgets::popup::Popup;
|
||||
use crate::ui::widgets::selectable_list::SelectableList;
|
||||
use crate::ui::{
|
||||
draw_help_footer_and_get_content_area, draw_large_popup_over, draw_list_box,
|
||||
draw_medium_popup_over, draw_prompt_box, draw_prompt_popup_over, DrawUi, ListProps,
|
||||
draw_large_popup_over, draw_medium_popup_over, draw_prompt_box, draw_prompt_popup_over, DrawUi,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -42,7 +43,8 @@ impl DrawUi for SystemDetailsUi {
|
||||
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
|
||||
match active_radarr_block {
|
||||
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 => {
|
||||
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)
|
||||
}
|
||||
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) {
|
||||
draw_list_box(
|
||||
f,
|
||||
area,
|
||||
|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)
|
||||
},
|
||||
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)
|
||||
)),
|
||||
},
|
||||
fn draw_logs_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
|
||||
let block = title_block("Log Details");
|
||||
let help_footer = 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) {
|
||||
@@ -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) {
|
||||
f.render_widget(title_block("Updates"), area);
|
||||
|
||||
let content_area = draw_help_footer_and_get_content_area(
|
||||
f,
|
||||
area,
|
||||
Some(format!(
|
||||
"<↑↓> scroll | {}",
|
||||
build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES)
|
||||
)),
|
||||
fn draw_updates_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
|
||||
let help_footer = format!(
|
||||
"<↑↓> scroll | {}",
|
||||
build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES)
|
||||
);
|
||||
let updates = app.data.radarr_data.updates.get_text();
|
||||
let block = borderless_block();
|
||||
let block = title_block("Updates");
|
||||
|
||||
if !updates.is_empty() {
|
||||
let updates_paragraph = Paragraph::new(Text::from(updates))
|
||||
.block(block)
|
||||
.block(borderless_block())
|
||||
.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 {
|
||||
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::layout::Rect;
|
||||
use ratatui::widgets::{Clear, Widget};
|
||||
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||
use ratatui::prelude::Text;
|
||||
use ratatui::widgets::{Block, Clear, Paragraph, Widget};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "popup_tests.rs"]
|
||||
mod popup_tests;
|
||||
|
||||
pub struct Popup<T: Widget> {
|
||||
pub struct Popup<'a, T: Widget> {
|
||||
widget: T,
|
||||
percent_x: 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 {
|
||||
Self {
|
||||
widget,
|
||||
percent_x,
|
||||
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) {
|
||||
let popup_area = centered_rect(self.percent_x, self.percent_y, area);
|
||||
|
||||
Clear.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) {
|
||||
self.render_popup(area, buf);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
mod tests {
|
||||
use crate::ui::widgets::popup::Popup;
|
||||
use pretty_assertions::assert_eq;
|
||||
use ratatui::layout::Alignment;
|
||||
use ratatui::widgets::Block;
|
||||
|
||||
#[test]
|
||||
@@ -11,5 +12,44 @@ mod tests {
|
||||
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);
|
||||
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::prelude::Widget;
|
||||
use ratatui::style::Style;
|
||||
use ratatui::widgets::{List, ListItem, StatefulWidget};
|
||||
use ratatui::widgets::{Block, List, ListItem, StatefulWidget};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "selectable_list_tests.rs"]
|
||||
@@ -17,6 +17,8 @@ where
|
||||
{
|
||||
content: &'a mut StatefulList<T>,
|
||||
row_mapper: F,
|
||||
highlight_style: Style,
|
||||
block: Block<'a>,
|
||||
}
|
||||
|
||||
impl<'a, T, F> SelectableList<'a, T, F>
|
||||
@@ -27,15 +29,27 @@ where
|
||||
Self {
|
||||
content,
|
||||
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) {
|
||||
let items: Vec<ListItem<'_>> = self.content.items.iter().map(&self.row_mapper).collect();
|
||||
|
||||
let selectable_list = List::new(items)
|
||||
.block(layout_block())
|
||||
.highlight_style(Style::new().highlight());
|
||||
.block(self.block)
|
||||
.highlight_style(self.highlight_style);
|
||||
|
||||
StatefulWidget::render(selectable_list, area, buf, &mut self.content.state);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
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 pretty_assertions::assert_eq;
|
||||
use ratatui::style::{Style, Stylize};
|
||||
use ratatui::widgets::ListItem;
|
||||
|
||||
#[test]
|
||||
@@ -17,5 +20,41 @@ mod tests {
|
||||
let row_mapper = selectable_list.row_mapper;
|
||||
assert_eq!(selectable_list.content.items, items);
|
||||
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