use ratatui::widgets::{Block, Borders, List, ListItem, StatefulWidget, Clear};
use ratatui::style::Style;
use ratatui::Frame;
use ratatui::layout::{Rect, Layout, Direction, Constraint, Alignment, Flex};
use ratatui::widgets::ListState;
use crate::Config;
use crate::tui::widgets::color::{parse_color, get_contrast_text_color};
use crate::tui::App;
use crate::tui::widgets::settings_list::render_settings_list;
pub fn render_settings_view(
f: &mut Frame,
area: Rect,
themes: &[String],
current_theme: &str,
_selected_index: usize,
list_state: &mut ListState,
config: &Config,
) {
if area.width < 2 || area.height < 2 {
return;
}
let active_theme = config.get_active_theme();
let fg_color = parse_color(&active_theme.fg);
let bg_color = parse_color(&active_theme.bg);
let highlight_bg = parse_color(&active_theme.highlight_bg);
let highlight_fg = get_contrast_text_color(highlight_bg);
let outer_block = Block::default()
.borders(Borders::ALL)
.title("Settings")
.style(Style::default().fg(fg_color).bg(bg_color));
f.render_widget(outer_block, area);
let inner_area = Rect::new(
area.x + 1,
area.y + 1,
area.width.saturating_sub(2),
area.height.saturating_sub(2),
);
let theme_box_height = (themes.len() + 2).max(5).min(inner_area.height as usize) as u16;
let theme_areas = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(theme_box_height), Constraint::Min(0), ])
.split(inner_area);
let theme_area = theme_areas[0];
let items: Vec<ListItem> = themes.iter().map(|theme_name| {
let is_selected = theme_name == current_theme;
let radio = if is_selected { "●" } else { "○" };
let text = format!("{} {}", radio, theme_name);
ListItem::new(text)
}).collect();
let list = List::new(items)
.block(Block::default().borders(Borders::ALL).title("Theme"))
.style(Style::default().fg(fg_color).bg(bg_color))
.highlight_style(
Style::default()
.fg(highlight_fg)
.bg(highlight_bg)
);
StatefulWidget::render(list, theme_area, f.buffer_mut(), list_state);
}
pub fn render_settings_view_modal(f: &mut Frame, area: Rect, app: &App) {
let active_theme = app.config.get_active_theme();
let fg_color = parse_color(&active_theme.fg);
let bg_color = parse_color(&active_theme.bg);
let highlight_bg = parse_color(&active_theme.highlight_bg);
let highlight_fg = get_contrast_text_color(highlight_bg);
let popup_area = popup_area(area, 70, 60);
f.render_widget(Clear, popup_area);
let outer_block = Block::default()
.borders(Borders::ALL)
.title("Settings")
.title_alignment(Alignment::Center)
.style(Style::default().fg(fg_color).bg(bg_color));
f.render_widget(outer_block, popup_area);
let inner_area = Rect::new(
popup_area.x + 1,
popup_area.y + 1,
popup_area.width.saturating_sub(2),
popup_area.height.saturating_sub(2),
);
let sidebar_width = (inner_area.width * 30 / 100).max(20).min(inner_area.width.saturating_sub(10));
let horizontal = Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Length(sidebar_width), Constraint::Min(1), ])
.split(inner_area);
let sidebar_area = horizontal[0];
let main_area = horizontal[1];
let categories = app.get_settings_categories();
let mut categories_list_state = app.settings.list_state.clone();
categories_list_state.select(Some(app.settings.category_index));
render_settings_list(f, sidebar_area, &categories, &mut categories_list_state, &app.config);
let selected_category = categories.get(app.settings.category_index);
match selected_category {
Some(category) if category == "Theme Settings" => {
render_theme_settings(f, main_area, app, fg_color, bg_color, highlight_fg, highlight_bg);
}
Some(category) if category == "Appearance Settings" => {
render_appearance_settings(f, main_area, app, fg_color, bg_color, highlight_fg, highlight_bg);
}
Some(category) if category == "Display Settings" => {
render_display_settings(f, main_area, app, fg_color, bg_color, highlight_fg, highlight_bg);
}
Some(category) if category == "System Settings" => {
render_system_settings(f, main_area, app, fg_color, bg_color);
}
_ => {
render_theme_settings(f, main_area, app, fg_color, bg_color, highlight_fg, highlight_bg);
}
}
}
fn render_theme_settings(
f: &mut Frame,
main_area: Rect,
app: &App,
fg_color: ratatui::style::Color,
bg_color: ratatui::style::Color,
highlight_fg: ratatui::style::Color,
highlight_bg: ratatui::style::Color,
) {
let themes = app.get_available_themes();
let current_theme = &app.config.current_theme;
let theme_box_height = (themes.len() + 2).max(5).min(main_area.height as usize) as u16;
let theme_areas = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(theme_box_height), Constraint::Min(0), ])
.split(main_area);
let theme_area = theme_areas[0];
let items: Vec<ListItem> = themes.iter().map(|theme_name| {
let is_selected = theme_name == current_theme;
let radio = if is_selected { "●" } else { "○" };
let text = format!("{} {}", radio, theme_name);
ListItem::new(text)
}).collect();
let list = List::new(items)
.block(Block::default().borders(Borders::ALL).title("Theme"))
.style(Style::default().fg(fg_color).bg(bg_color))
.highlight_style(
Style::default()
.fg(highlight_fg)
.bg(highlight_bg)
);
let mut list_state = app.settings.theme_list_state.clone();
list_state.select(Some(app.settings.theme_index));
StatefulWidget::render(list, theme_area, f.buffer_mut(), &mut list_state);
}
fn render_appearance_settings(
f: &mut Frame,
main_area: Rect,
app: &App,
fg_color: ratatui::style::Color,
bg_color: ratatui::style::Color,
highlight_fg: ratatui::style::Color,
highlight_bg: ratatui::style::Color,
) {
let width_options = app.get_sidebar_width_options();
let current_width = app.config.sidebar_width_percent;
let width_box_height = (width_options.len() + 2).max(5).min(main_area.height as usize) as u16;
let width_areas = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(width_box_height), Constraint::Min(0), ])
.split(main_area);
let width_area = width_areas[0];
let items: Vec<ListItem> = width_options.iter().map(|&width| {
let is_selected = width == current_width;
let radio = if is_selected { "●" } else { "○" };
let text = format!("{} {}%", radio, width);
ListItem::new(text)
}).collect();
let list = List::new(items)
.block(Block::default().borders(Borders::ALL).title("Sidebar Width"))
.style(Style::default().fg(fg_color).bg(bg_color))
.highlight_style(
Style::default()
.fg(highlight_fg)
.bg(highlight_bg)
);
let mut list_state = ListState::default();
list_state.select(Some(app.settings.sidebar_width_index));
StatefulWidget::render(list, width_area, f.buffer_mut(), &mut list_state);
}
fn render_display_settings(
f: &mut Frame,
main_area: Rect,
app: &App,
fg_color: ratatui::style::Color,
bg_color: ratatui::style::Color,
highlight_fg: ratatui::style::Color,
highlight_bg: ratatui::style::Color,
) {
use crate::tui::app::ListViewMode;
let mode_options = vec!["Simple", "TwoLine", "GroupedByTags"];
let current_mode_str = match app.ui.list_view_mode {
ListViewMode::Simple => "Simple",
ListViewMode::TwoLine => "TwoLine",
ListViewMode::GroupedByTags => "GroupedByTags",
};
let mode_box_height = (mode_options.len() + 2).max(5).min(main_area.height as usize) as u16;
let mode_areas = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(mode_box_height), Constraint::Min(0), ])
.split(main_area);
let mode_area = mode_areas[0];
let items: Vec<ListItem> = mode_options.iter().map(|&mode| {
let is_selected = mode == current_mode_str;
let radio = if is_selected { "●" } else { "○" };
let text = format!("{} {}", radio, mode);
ListItem::new(text)
}).collect();
let list = List::new(items)
.block(Block::default().borders(Borders::ALL).title("Display Mode"))
.style(Style::default().fg(fg_color).bg(bg_color))
.highlight_style(
Style::default()
.fg(highlight_fg)
.bg(highlight_bg)
);
let mut list_state = ListState::default();
list_state.select(Some(app.settings.display_mode_index));
StatefulWidget::render(list, mode_area, f.buffer_mut(), &mut list_state);
}
fn render_system_settings(
f: &mut Frame,
main_area: Rect,
app: &App,
fg_color: ratatui::style::Color,
bg_color: ratatui::style::Color,
) {
use ratatui::widgets::Paragraph;
let config_path = app.get_config_file_path();
let db_path = app.get_database_file_path();
let content = format!(
"Config File:\n{}\n\nDatabase File:\n{}",
config_path,
db_path
);
let paragraph = Paragraph::new(content)
.block(Block::default().borders(Borders::ALL).title("File Locations"))
.style(Style::default().fg(fg_color).bg(bg_color))
.wrap(ratatui::widgets::Wrap { trim: true });
f.render_widget(paragraph, main_area);
}
fn popup_area(area: Rect, percent_x: u16, percent_y: u16) -> Rect {
let vertical = Layout::vertical([Constraint::Percentage(percent_y)]).flex(Flex::Center);
let horizontal = Layout::horizontal([Constraint::Percentage(percent_x)]).flex(Flex::Center);
let [area] = vertical.areas(area);
let [area] = horizontal.areas(area);
area
}