use ratatui::{text::Line, widgets::ListItem};
use ratatui_kit::prelude::*;
use crate::{
components::{search_input::SearchInput, select::Select},
hooks::UseThemeConfig,
};
#[derive(Default, Clone)]
pub struct ChapterName(pub String, pub usize);
impl From<(String, usize)> for ChapterName {
fn from(value: (String, usize)) -> Self {
Self(value.0, value.1)
}
}
impl From<ChapterName> for ListItem<'_> {
fn from(value: ChapterName) -> Self {
ListItem::new(value.0)
}
}
#[derive(Default, Props)]
pub struct SelectChapterProps {
pub is_editing: bool,
pub chapters: Vec<ChapterName>,
pub on_select: Handler<'static, usize>,
pub default_value: Option<usize>,
}
#[component]
pub fn SelectChapter(
props: &mut SelectChapterProps,
mut hooks: Hooks,
) -> impl Into<AnyElement<'static>> {
let mut filter_text = hooks.use_state(String::default);
let theme = hooks.use_theme_config();
let is_inputting = *hooks.use_context::<State<bool>>();
let state = hooks.use_state(ratatui::widgets::ListState::default);
let is_editing = props.is_editing;
let items = hooks.use_memo(
|| {
if filter_text.read().is_empty() {
props.chapters.clone()
} else {
props
.chapters
.iter()
.filter(|&chapter_name| {
if filter_text.read().starts_with('$') {
let index_str = &filter_text.read()[1..];
if let Ok(index) = index_str.parse::<usize>() {
index == chapter_name.1
} else {
false
}
} else {
chapter_name.0.contains(filter_text.read().as_str())
}
})
.cloned()
.collect::<Vec<_>>()
}
},
(filter_text.read().clone(), props.chapters.len()),
);
let mut on_select = props.on_select.take();
element!(View {
SearchInput(
placeholder: "按s搜索章节,以$开头输入数字表示索引",
on_submit: move |text| {
filter_text.set(text);
true
},
clear_on_escape: true,
on_clear: move |_| {
filter_text.set(String::default());
},
validate: |input: String| {
if let Some(stripped) = input.strip_prefix('$') {
if stripped.parse::<usize>().is_ok() {
(true, "".to_owned())
} else {
(false, "请输入正确的数字".to_owned())
}
} else {
(true, "".to_owned())
}
},
is_editing: is_editing,
)
Select<ChapterName>(
top_title: Line::from("目录").style(theme.basic.border_title).centered(),
empty_message: if filter_text.read().is_empty() {
"暂无章节".to_owned()
} else {
"无匹配章节".to_owned()
},
on_select: move |item: ChapterName| {
on_select(item.1);
},
is_editing: !is_inputting.get() && is_editing,
state: state,
bottom_title: Line::from(
format!(
"{}/{}",
state.read().selected().unwrap_or(0) + 1,
items.len()
)
).style(theme.basic.border_info),
items: items,
default_value: props.default_value,
)
})
}