use ratatui::{
style::{Modifier, Style},
text::Span,
};
use crate::state::AppState;
use crate::theme::theme;
use super::super::{FilterStates, OptionalRepos};
use super::types::TitleI18nStrings;
pub(super) fn get_button_style(is_open: bool) -> Style {
let th = theme();
if is_open {
Style::default()
.fg(th.crust)
.bg(th.mauve)
.add_modifier(Modifier::BOLD)
} else {
Style::default()
.fg(th.mauve)
.bg(th.surface2)
.add_modifier(Modifier::BOLD)
}
}
pub(super) fn render_button_with_underline(label: &str, style: Style) -> Vec<Span<'static>> {
let mut spans = Vec::new();
if let Some(first) = label.chars().next() {
let rest = &label[first.len_utf8()..];
spans.push(Span::styled(
first.to_string(),
style.add_modifier(Modifier::UNDERLINED),
));
spans.push(Span::styled(rest.to_string(), style));
} else {
spans.push(Span::styled(label.to_string(), style));
}
spans
}
fn create_filter_renderer() -> impl Fn(&str, bool) -> Span<'static> {
let th = theme();
move |label: &str, on: bool| -> Span<'static> {
let (fg, bg) = if on {
(th.crust, th.green)
} else {
(th.mauve, th.surface2)
};
Span::styled(
format!("[{label}]"),
Style::default().fg(fg).bg(bg).add_modifier(Modifier::BOLD),
)
}
}
fn render_optional_filter(
has_repo: bool,
label: &str,
is_active: bool,
filt: &dyn Fn(&str, bool) -> Span<'static>,
) -> Option<Span<'static>> {
if has_repo {
Some(filt(label, is_active))
} else {
None
}
}
pub(super) fn render_title_prefix(
i18n: &TitleI18nStrings,
results_len: usize,
) -> Vec<Span<'static>> {
let th = theme();
let results_title_text = format!("{} ({})", i18n.results_title, results_len);
vec![Span::styled(
results_title_text,
Style::default().fg(th.overlay1),
)]
}
pub(super) fn render_sort_button(i18n: &TitleI18nStrings, is_open: bool) -> Vec<Span<'static>> {
let sort_button_label = format!("{} v", i18n.sort_button);
let btn_style = get_button_style(is_open);
vec![Span::styled(sort_button_label, btn_style)]
}
pub(super) fn render_core_filters(
i18n: &TitleI18nStrings,
filter_states: &FilterStates,
) -> Vec<Span<'static>> {
let filt = create_filter_renderer();
vec![
filt(&i18n.filter_aur, filter_states.show_aur),
Span::raw(" "),
filt(&i18n.filter_core, filter_states.show_core),
Span::raw(" "),
filt(&i18n.filter_extra, filter_states.show_extra),
Span::raw(" "),
filt(&i18n.filter_multilib, filter_states.show_multilib),
]
}
pub(super) fn render_optional_eos_cachyos_filters(
i18n: &TitleI18nStrings,
optional_repos: &OptionalRepos,
filter_states: &FilterStates,
) -> Vec<Span<'static>> {
let filt = create_filter_renderer();
let mut spans = Vec::new();
if let Some(span) = render_optional_filter(
optional_repos.has_eos,
&i18n.filter_eos,
filter_states.show_eos,
&filt,
) {
spans.push(Span::raw(" "));
spans.push(span);
}
if let Some(span) = render_optional_filter(
optional_repos.has_cachyos,
&i18n.filter_cachyos,
filter_states.show_cachyos,
&filt,
) {
spans.push(Span::raw(" "));
spans.push(span);
}
spans
}
pub(super) fn render_artix_filter(
i18n: &TitleI18nStrings,
optional_repos: &OptionalRepos,
filter_states: &FilterStates,
show_artix_specific_repos: bool,
) -> Vec<Span<'static>> {
let mut spans = Vec::new();
if optional_repos.has_artix {
spans.push(Span::raw(" "));
let artix_text = if show_artix_specific_repos {
format!("[{}]", i18n.filter_artix)
} else {
format!("[{}] v", i18n.filter_artix)
};
let th = theme();
let (fg, bg) = if filter_states.show_artix {
(th.crust, th.green)
} else {
(th.mauve, th.surface2)
};
spans.push(Span::styled(
artix_text,
Style::default().fg(fg).bg(bg).add_modifier(Modifier::BOLD),
));
}
spans
}
pub(super) fn render_artix_specific_filters(
i18n: &TitleI18nStrings,
optional_repos: &OptionalRepos,
filter_states: &FilterStates,
) -> Vec<Span<'static>> {
let filt = create_filter_renderer();
let mut spans = Vec::new();
let artix_filters = [
(
optional_repos.has_artix_omniverse,
&i18n.filter_artix_omniverse,
filter_states.show_artix_omniverse,
),
(
optional_repos.has_artix_universe,
&i18n.filter_artix_universe,
filter_states.show_artix_universe,
),
(
optional_repos.has_artix_lib32,
&i18n.filter_artix_lib32,
filter_states.show_artix_lib32,
),
(
optional_repos.has_artix_galaxy,
&i18n.filter_artix_galaxy,
filter_states.show_artix_galaxy,
),
(
optional_repos.has_artix_world,
&i18n.filter_artix_world,
filter_states.show_artix_world,
),
(
optional_repos.has_artix_system,
&i18n.filter_artix_system,
filter_states.show_artix_system,
),
];
for (has_repo, label, is_active) in artix_filters {
if let Some(span) = render_optional_filter(has_repo, label, is_active, &filt) {
spans.push(Span::raw(" "));
spans.push(span);
}
}
spans
}
pub(super) fn render_blackarch_filter(
i18n: &TitleI18nStrings,
optional_repos: &OptionalRepos,
filter_states: &FilterStates,
) -> Vec<Span<'static>> {
let filt = create_filter_renderer();
let mut spans = Vec::new();
if let Some(span) = render_optional_filter(
optional_repos.has_blackarch,
&i18n.filter_blackarch,
filter_states.show_blackarch,
&filt,
) {
spans.push(Span::raw(" "));
spans.push(span);
}
spans
}
pub(super) fn render_manjaro_filter(
i18n: &TitleI18nStrings,
optional_repos: &OptionalRepos,
filter_states: &FilterStates,
) -> Vec<Span<'static>> {
let filt = create_filter_renderer();
let mut spans = Vec::new();
if let Some(span) = render_optional_filter(
optional_repos.has_manjaro,
&i18n.filter_manjaro,
filter_states.show_manjaro,
&filt,
) {
spans.push(Span::raw(" "));
spans.push(span);
}
spans
}
pub(super) fn render_custom_repos_dynamic_chip(
app: &AppState,
chip_label: Option<&str>,
) -> Vec<Span<'static>> {
let Some(label) = chip_label else {
return Vec::new();
};
let th = theme();
let all_on = !app.results_filter_dynamic.is_empty()
&& app.results_filter_dynamic.values().all(|visible| *visible);
let (fg, bg) = if all_on {
(th.crust, th.green)
} else {
(th.mauve, th.surface2)
};
vec![
Span::raw(" "),
Span::styled(
label.to_string(),
Style::default().fg(fg).bg(bg).add_modifier(Modifier::BOLD),
),
]
}