1use crate::Book;
4
5pub const ENTRIES_FIRST: usize = 11;
7pub const ENTRIES_PER: usize = 13;
9
10#[derive(Debug, Clone)]
11pub struct BookViewState {
12 pub cat: usize,
13 pub entry: usize, pub page: usize,
15 pub at_home: bool,
16 pub list_spread: usize, }
18
19impl Default for BookViewState {
20 fn default() -> Self {
21 Self { cat: 0, entry: 0, page: 0, at_home: true, list_spread: 0 }
22 }
23}
24
25impl BookViewState {
26 pub fn handle(&mut self, ev: &str, book: &Book) -> bool {
28 if ev == "home" {
29 if !self.at_home { self.at_home = true; return true; }
30 } else if let Some(n) = ev.strip_prefix("cat:") {
31 if let Ok(i) = n.parse::<usize>() {
32 if i < book.categories.len() {
33 let changed = self.at_home || i != self.cat;
34 self.cat = i;
35 self.entry = 0;
36 self.page = 0;
37 self.list_spread = 0;
38 self.at_home = false;
39 return changed;
40 }
41 }
42 } else if let Some(n) = ev.strip_prefix("entry:") {
43 if let Ok(i) = n.parse::<usize>() {
45 let total = self.entries_in_cat(book).len();
46 if i < total && (i != self.entry || self.page != 0) {
47 self.entry = i;
48 self.page = 0;
49 return true;
50 }
51 }
52 } else if ev == "prev_page" {
53 if self.page > 0 { self.page -= 1; return true; }
54 } else if ev == "next_page" {
55 if self.page + 1 < self.page_count(book) {
56 self.page += 1; return true;
57 }
58 } else if ev == "prev_list" {
59 if self.list_spread > 0 { self.list_spread -= 1; return true; }
60 } else if ev == "next_list" {
61 if self.list_spread + 1 < self.list_spread_count(book) {
62 self.list_spread += 1; return true;
63 }
64 }
65 false
66 }
67
68 pub fn entries_in_cat<'b>(&self, book: &'b Book) -> Vec<&'b crate::BookEntry> {
70 let cat_id = book.categories.get(self.cat).map(|c| c.id.as_str()).unwrap_or("");
71 book.entries.iter().filter(|e| e.category == cat_id).collect()
72 }
73
74 pub fn list_spread_count(&self, book: &Book) -> usize {
76 let total = self.entries_in_cat(book).len();
77 if total <= ENTRIES_FIRST { return 1; }
78 1 + (total - ENTRIES_FIRST + ENTRIES_PER - 1) / ENTRIES_PER
79 }
80
81 pub fn list_spread_start(&self) -> usize {
83 if self.list_spread == 0 { 0 }
84 else { ENTRIES_FIRST + (self.list_spread - 1) * ENTRIES_PER }
85 }
86
87 pub fn entries_visible<'b>(&self, book: &'b Book) -> Vec<&'b crate::BookEntry> {
89 let all = self.entries_in_cat(book);
90 let start = self.list_spread_start();
91 let count = if self.list_spread == 0 { ENTRIES_FIRST } else { ENTRIES_PER };
92 all.into_iter().skip(start).take(count).collect()
93 }
94
95 pub fn current_entry<'b>(&self, book: &'b Book) -> Option<&'b crate::BookEntry> {
96 self.entries_in_cat(book).into_iter().nth(self.entry)
97 }
98
99 pub fn page_count(&self, book: &Book) -> usize {
100 self.current_entry(book).map(|e| e.pages.len().max(1)).unwrap_or(1)
101 }
102}