feat: improve HTML text extraction with paragraph preservation, add reading margins, paragraph-aware pagination
This commit is contained in:
@@ -160,14 +160,22 @@ pub fn reading_view(
|
||||
|
||||
// --- Center text area ---
|
||||
egui::CentralPanel::default().show_inside(ui, |ui| {
|
||||
let (rect, response) = ui.allocate_at_least(ui.available_size(), egui::Sense::click());
|
||||
let available = ui.available_size();
|
||||
let (rect, response) = ui.allocate_at_least(available, egui::Sense::click());
|
||||
|
||||
// Add reading margins (inset)
|
||||
let inset = 24.0;
|
||||
let text_rect = egui::Rect::from_min_size(
|
||||
egui::pos2(rect.min.x + inset, rect.min.y),
|
||||
egui::vec2((rect.width() - inset * 2.0).max(100.0), rect.height()),
|
||||
);
|
||||
|
||||
if let Some(section) = book.sections.get(*current_section) {
|
||||
if *current_page < section.pages.len().saturating_sub(1) {
|
||||
let start = section.pages[*current_page];
|
||||
let end = section.pages[*current_page + 1];
|
||||
let text: String = section.content.chars().skip(start).take(end - start).collect();
|
||||
ui.put(rect, |ui: &mut egui::Ui| {
|
||||
ui.put(text_rect, |ui: &mut egui::Ui| {
|
||||
ui.add(
|
||||
egui::Label::new(
|
||||
egui::RichText::new(&text)
|
||||
@@ -242,15 +250,49 @@ pub fn calculate_pages(text: &str, chars_per_page: usize) -> Vec<usize> {
|
||||
return pages;
|
||||
}
|
||||
|
||||
let total_chars = text.chars().count();
|
||||
let chars: Vec<char> = text.chars().collect();
|
||||
let total_chars = chars.len();
|
||||
if total_chars <= chars_per_page {
|
||||
pages.push(total_chars);
|
||||
return pages;
|
||||
}
|
||||
|
||||
let mut pos = 0;
|
||||
let mut pos: usize = 0;
|
||||
while pos < total_chars {
|
||||
pos = (pos + chars_per_page).min(total_chars);
|
||||
let next = pos + chars_per_page;
|
||||
if next >= total_chars {
|
||||
pages.push(total_chars);
|
||||
break;
|
||||
}
|
||||
|
||||
// Search backward from next for paragraph (\n\n) or line (\n) breaks
|
||||
let search_start = pos + chars_per_page / 2;
|
||||
let search_end = (next + chars_per_page / 2).min(total_chars);
|
||||
let mut split = next;
|
||||
|
||||
// Prefer double newline (paragraph), then single newline
|
||||
let mut found = false;
|
||||
for i in (search_start..search_end).rev() {
|
||||
if chars[i] == '\n' && i > 0 && chars[i - 1] == '\n' {
|
||||
split = i - 1;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
for i in (search_start..search_end).rev() {
|
||||
if chars[i] == '\n' {
|
||||
split = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if split <= pos {
|
||||
split = next;
|
||||
}
|
||||
|
||||
pos = split.min(total_chars);
|
||||
pages.push(pos);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user