use anyhow::{Context, Result};
use cursive::{
align::HAlign,
view::{Nameable, Resizable, Scrollable},
views::{Button, LinearLayout, SelectView, TextView},
Cursive,
};
use crate::{
config::CONFIG,
ui::{
article::on_article_submit, panel::WithPanel, search::on_continue_submit,
utils::percentage, views::RootLayout,
},
wiki::search::{Search, SearchResult},
};
use super::on_result_select;
const SEARCH_WIDTH_PERCENTAGE: f32 = 0.7;
const SEARCH_HEIGHT_PERCENTAGE: f32 = 0.6;
const PREVIEW_HEIGHT_PERCENTAGE: f32 = 0.5;
const SEARCH_RESULTS_PERCENTAGE: f32 = 0.3;
pub fn display_search_results(siv: &mut Cursive, search: Search, query: &str) -> Result<()> {
info!("displaying '{}' search results", search.results().count());
let screen_size = siv.screen_size();
debug!("screen_size: '{}' '{}'", screen_size.x, screen_size.y);
let search_width = percentage(screen_size.x, SEARCH_WIDTH_PERCENTAGE);
let search_height = percentage(screen_size.y, SEARCH_HEIGHT_PERCENTAGE);
debug!("search_width: '{}'", search_width);
debug!("search_height: '{}'", search_height);
let search_results_width = percentage(search_width, SEARCH_RESULTS_PERCENTAGE);
let search_preview_height = percentage(search_height, PREVIEW_HEIGHT_PERCENTAGE);
debug!("search_results_width: '{}'", search_results_width);
debug!("search_preview_height: '{}'", search_preview_height);
let layer_len = siv.screen_mut().len() + 1;
let search_results_view_name = format!("search_results_view-{}", layer_len);
let search_continue_button_name = format!("search_continue_button-{}", layer_len);
let search_result_preview_name = format!("search_result_preview-{}", layer_len);
let search_result_info_name = format!("search_result_info-{}", layer_len);
debug!("search_results_view name '{}'", search_results_view_name);
debug!(
"search_continue_button name '{}'",
search_continue_button_name
);
debug!(
"search_result_preview name '{}'",
search_result_preview_name
);
debug!("search_result_info name '{}'", search_result_info_name);
let search_results_view = {
let mut search_results_view = SelectView::<SearchResult>::new()
.on_select(on_result_select)
.on_submit(on_article_submit);
for search_result in search.results() {
search_results_view
.add_item(search_result.title().to_string(), search_result.to_owned());
}
search_results_view
}
.with_name(search_results_view_name)
.full_height()
.fixed_width(search_results_width)
.scrollable();
let search_continue_button = {
let query = query.to_string();
let offset = search.search_offset().to_owned();
Button::new("Show more results...", move |s| {
on_continue_submit(s, &query, &offset)
})
.with_name(search_continue_button_name)
};
let search_result_preview = TextView::new("Test")
.h_align(HAlign::Left)
.with_name(search_result_preview_name)
.with_panel()
.fixed_height(search_preview_height)
.full_width();
let search_result_info = TextView::empty()
.with_name(search_result_info_name)
.with_panel()
.full_height();
let search_status_view = {
let mut search_status_view = TextView::empty();
if let Some(total_hits) = search.info().total_hits() {
search_status_view.set_content(format!(
"Found {} articles matching your search",
total_hits
));
}
search_status_view
};
debug!("created the views for the search results layout");
let search_results_layout = LinearLayout::vertical()
.child(search_results_view)
.child(search_continue_button)
.with_panel();
let search_result_detail_layout = LinearLayout::vertical()
.child(search_result_preview)
.child(search_result_info);
let search_layout = RootLayout::horizontal(CONFIG.keybindings.clone())
.child(search_results_layout)
.child(search_result_detail_layout);
debug!("added the views to the search layout");
siv.add_layer(
LinearLayout::vertical()
.child(search_layout)
.child(search_status_view)
.with_panel()
.title(format!("Results for '{}'", query))
.fixed_width(search_width)
.fixed_height(search_height),
);
debug!("added the layouts to a new layer");
if let Err(error) = siv.cb_sink().send(Box::new(move |s| {
if let Some(search_result) = search.results().next() {
on_result_select(s, search_result);
}
})) {
warn!("{:?}", error);
bail!("couldn't send the callback to select the first search result");
}
debug!("send the callback for selecting the first search result");
Ok(())
}
pub fn display_more_search_results(
siv: &mut Cursive,
search: Search,
search_query: &str,
) -> Result<()> {
info!(
"displaying '{}' more search results",
search.results().count()
);
let layer_len = siv.screen_mut().len();
let search_results_view_name = format!("search_results_view-{}", layer_len);
let search_continue_button_name = format!("search_continue_button-{}", layer_len);
let mut search_results_views = siv
.find_name::<SelectView<SearchResult>>(&search_results_view_name)
.context(format!("couldn't find '{}'", search_results_view_name))?;
debug!("found the search_results_view");
let mut search_continue_button = siv
.find_name::<Button>(&search_continue_button_name)
.context(format!("couldn't find '{}'", search_continue_button_name))?;
debug!("found the search_continue_button");
for search_result in search.results() {
search_results_views.add_item(search_result.title(), search_result.clone())
}
debug!("added the results to the results view");
{
let query = search_query.to_string();
search_continue_button
.set_callback(move |s| on_continue_submit(s, &query, search.search_offset()));
}
debug!("set the new callback of the continue button");
siv.focus_name(&search_results_view_name)
.context(format!("failed to focus '{}'", search_results_view_name))?;
debug!("focussed the search_results_view");
Ok(())
}