feat: improve HTML text extraction with paragraph preservation, add reading margins, paragraph-aware pagination

This commit is contained in:
Developer
2026-05-14 20:43:29 +08:00
parent b0071c6617
commit 16f801cdf8
2 changed files with 248 additions and 33 deletions

View File

@@ -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);
}