mirror of
https://github.com/imgurbot12/rmenu.git
synced 2025-01-27 21:38:14 +01:00
feat: paginated results
This commit is contained in:
parent
7c3c3cf486
commit
3f4fd61aa8
3 changed files with 75 additions and 25 deletions
|
@ -73,6 +73,8 @@ struct IndexTemplate<'a> {
|
|||
#[derive(Template)]
|
||||
#[template(path = "results.html")]
|
||||
struct ResultsTemplate<'a> {
|
||||
start: usize,
|
||||
end: usize,
|
||||
results: &'a Vec<&'a Entry>,
|
||||
config: &'a Config,
|
||||
}
|
||||
|
@ -81,6 +83,7 @@ struct ResultsTemplate<'a> {
|
|||
struct AppState<'a> {
|
||||
pos: usize,
|
||||
subpos: usize,
|
||||
page: usize,
|
||||
search: String,
|
||||
results: Vec<&'a Entry>,
|
||||
data: &'a AppData,
|
||||
|
@ -97,27 +100,40 @@ impl<'a> AppState<'a> {
|
|||
Self {
|
||||
pos: 0,
|
||||
subpos: 0,
|
||||
page: 0,
|
||||
search: "".to_owned(),
|
||||
results: vec![],
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
/// Update AppState w/ new Search and Render HTML Results
|
||||
fn search(&mut self, search: String) -> String {
|
||||
// update search and calculate matching results
|
||||
let sfn = build_searchfn(&self.data.config, &search);
|
||||
self.pos = 0;
|
||||
self.search = search;
|
||||
self.results = self.data.entries.iter().filter(|e| sfn(e)).collect();
|
||||
/// Render Current Page of Results
|
||||
fn render_results_page(&self) -> String {
|
||||
let size = self.data.config.page_size;
|
||||
let start = self.page * size;
|
||||
let max = (self.page + 1) * size;
|
||||
let nresults = std::cmp::max(self.results.len(), 1);
|
||||
let end = std::cmp::min(max, nresults - 1);
|
||||
// generate results html from template
|
||||
let template = ResultsTemplate {
|
||||
start,
|
||||
end,
|
||||
config: &self.data.config,
|
||||
results: &self.results,
|
||||
};
|
||||
template.render().unwrap()
|
||||
}
|
||||
|
||||
/// Update AppState w/ new Search and Render HTML Results
|
||||
fn search(&mut self, search: String) -> String {
|
||||
let sfn = build_searchfn(&self.data.config, &search);
|
||||
self.pos = 0;
|
||||
self.page = 0;
|
||||
self.search = search;
|
||||
self.results = self.data.entries.iter().filter(|e| sfn(e)).collect();
|
||||
self.render_results_page()
|
||||
}
|
||||
|
||||
/// Execute Action associated w/ Current Position/Subposition
|
||||
fn execute(&self) {
|
||||
log::debug!("execute {} {}", self.pos, self.subpos);
|
||||
|
@ -132,14 +148,36 @@ impl<'a> AppState<'a> {
|
|||
execute(action, self.data.config.terminal.clone());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn move_up(&mut self, up: usize) {
|
||||
self.pos = std::cmp::max(self.pos, up) - up;
|
||||
/// Return Additional Page Results to Load (when nessesary)
|
||||
fn append_results(&mut self, smooth: bool) -> Option<String> {
|
||||
let pos = self.pos as f64;
|
||||
let size = self.data.config.page_size as f64;
|
||||
let pages = pos / size;
|
||||
let ratio = (pos % size) / size;
|
||||
if pages > self.page as f64 && ratio > self.data.config.page_load {
|
||||
println!("loading next page!");
|
||||
self.page += 1;
|
||||
let results = self.render_results_page();
|
||||
return Some(format!("append({}, {results:?}, {smooth})", self.pos));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn move_down(&mut self, down: usize) {
|
||||
self.pos = std::cmp::min(self.pos + down, self.results.len() - 1);
|
||||
fn move_up(&mut self, up: usize) -> Option<String> {
|
||||
self.pos = std::cmp::max(self.pos, up) - up;
|
||||
Some(format!("setpos({})", self.pos))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn move_down(&mut self, down: usize) -> Option<String> {
|
||||
let max = (self.page + 1) * self.data.config.page_size;
|
||||
let end = std::cmp::min(max, self.results.len()) - 1;
|
||||
self.pos = std::cmp::min(self.pos + down, end);
|
||||
match self.append_results(false) {
|
||||
Some(operation) => Some(operation),
|
||||
None => Some(format!("setpos({})", self.pos)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle Search Event sent by UI
|
||||
|
@ -148,8 +186,6 @@ impl<'a> AppState<'a> {
|
|||
Some(format!("update({results:?})"))
|
||||
}
|
||||
|
||||
//TODO: need to increase page-size as cursor moves down
|
||||
//TODO: add loading on scroll as well
|
||||
//TODO: add submenu access and selection
|
||||
//TODO: put back main to reference actual config
|
||||
//TODO: update sway config to make borderless
|
||||
|
@ -165,11 +201,9 @@ impl<'a> AppState<'a> {
|
|||
} else if matches(&keybinds.exit, &mods, &code) {
|
||||
std::process::exit(0);
|
||||
} else if matches(&keybinds.move_next, &mods, &code) {
|
||||
self.move_down(1);
|
||||
Some(format!("setpos({})", self.pos))
|
||||
self.move_down(1)
|
||||
} else if matches(&keybinds.move_prev, &mods, &code) {
|
||||
self.move_up(1);
|
||||
Some(format!("setpos({})", self.pos))
|
||||
self.move_up(1)
|
||||
} else if matches(&keybinds.open_menu, &mods, &code) {
|
||||
// k_updater.set_event(KeyEvent::OpenMenu);
|
||||
None
|
||||
|
@ -177,11 +211,9 @@ impl<'a> AppState<'a> {
|
|||
// k_updater.set_event(KeyEvent::CloseMenu);
|
||||
None
|
||||
} else if matches(&keybinds.jump_next, &mods, &code) {
|
||||
self.move_down(self.data.config.jump_dist);
|
||||
Some(format!("setpos({})", self.pos))
|
||||
self.move_down(self.data.config.jump_dist)
|
||||
} else if matches(&keybinds.jump_prev, &mods, &code) {
|
||||
self.move_up(self.data.config.jump_dist);
|
||||
Some(format!("setpos({})", self.pos))
|
||||
self.move_up(self.data.config.jump_dist)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -206,7 +238,10 @@ impl<'a> AppState<'a> {
|
|||
if let Some((pos, subpos)) = self.parse_id_pos(&id) {
|
||||
self.pos = pos;
|
||||
self.subpos = subpos;
|
||||
return Some(format!("setpos({pos}, true)"));
|
||||
return match self.append_results(true) {
|
||||
Some(op) => Some(op),
|
||||
None => Some(format!("setpos({pos}, true)")),
|
||||
};
|
||||
}
|
||||
}
|
||||
ClickEvent::Double { id } => {
|
||||
|
@ -222,7 +257,13 @@ impl<'a> AppState<'a> {
|
|||
|
||||
/// Handle Scrolling Events sent by UI
|
||||
fn scroll_event(&mut self, event: ScrollEvent) -> Option<String> {
|
||||
println!("scroll: {event:?}");
|
||||
// load additonal results when scrolled near bottom
|
||||
let ratio = event.y as f64 / event.maxy as f64;
|
||||
if ratio >= self.data.config.page_load {
|
||||
self.page += 1;
|
||||
let results = self.render_results_page();
|
||||
return Some(format!("append(null, {results:?})"));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{%- for (i, entry) in results.iter().enumerate() %}
|
||||
{%- for i in start..end %}
|
||||
{% let entry = results[i] %}
|
||||
<div class="result-entry">
|
||||
<div
|
||||
id="result-{{ i }}"
|
||||
|
|
|
@ -70,6 +70,14 @@ function update(html) {
|
|||
setpos(0);
|
||||
}
|
||||
|
||||
// Append Results HTML
|
||||
function append(pos, html, smooth = false) {
|
||||
results.innerHTML += html;
|
||||
if (pos != null && pos != undefined) {
|
||||
setpos(pos, smooth);
|
||||
}
|
||||
}
|
||||
|
||||
/* Init */
|
||||
|
||||
// start position at zero
|
||||
|
|
Loading…
Reference in a new issue