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 {
22 cat: 0,
23 entry: 0,
24 page: 0,
25 at_home: true,
26 list_spread: 0,
27 }
28 }
29}
30
31impl BookViewState {
32 pub fn handle(&mut self, ev: &str, book: &Book) -> bool {
34 if ev == "home" {
35 if !self.at_home {
36 self.at_home = true;
37 return true;
38 }
39 } else if let Some(n) = ev.strip_prefix("cat:") {
40 if let Ok(i) = n.parse::<usize>()
41 && i < book.categories.len()
42 {
43 let changed = self.at_home || i != self.cat;
44 self.cat = i;
45 self.entry = 0;
46 self.page = 0;
47 self.list_spread = 0;
48 self.at_home = false;
49 return changed;
50 }
51 } else if let Some(n) = ev.strip_prefix("entry:") {
52 if let Ok(i) = n.parse::<usize>() {
54 let total = self.entries_in_cat(book).len();
55 if i < total && (i != self.entry || self.page != 0) {
56 self.entry = i;
57 self.page = 0;
58 return true;
59 }
60 }
61 } else if ev == "prev_page" {
62 if self.page > 0 {
63 self.page -= 1;
64 return true;
65 }
66 } else if ev == "next_page" {
67 if self.page + 1 < self.page_count(book) {
68 self.page += 1;
69 return true;
70 }
71 } else if ev == "prev_list" {
72 if self.list_spread > 0 {
73 self.list_spread -= 1;
74 return true;
75 }
76 } else if ev == "next_list" && self.list_spread + 1 < self.list_spread_count(book) {
77 self.list_spread += 1;
78 return true;
79 }
80 false
81 }
82
83 pub fn entries_in_cat<'b>(&self, book: &'b Book) -> Vec<&'b crate::BookEntry> {
85 let cat_id = book
86 .categories
87 .get(self.cat)
88 .map(|c| c.id.as_str())
89 .unwrap_or("");
90 book.entries
91 .iter()
92 .filter(|e| e.category == cat_id)
93 .collect()
94 }
95
96 pub fn list_spread_count(&self, book: &Book) -> usize {
98 let total = self.entries_in_cat(book).len();
99 if total <= ENTRIES_FIRST {
100 return 1;
101 }
102 1 + (total - ENTRIES_FIRST).div_ceil(ENTRIES_PER)
103 }
104
105 pub fn list_spread_start(&self) -> usize {
107 if self.list_spread == 0 {
108 0
109 } else {
110 ENTRIES_FIRST + (self.list_spread - 1) * ENTRIES_PER
111 }
112 }
113
114 pub fn entries_visible<'b>(&self, book: &'b Book) -> Vec<&'b crate::BookEntry> {
116 let all = self.entries_in_cat(book);
117 let start = self.list_spread_start();
118 let count = if self.list_spread == 0 {
119 ENTRIES_FIRST
120 } else {
121 ENTRIES_PER
122 };
123 all.into_iter().skip(start).take(count).collect()
124 }
125
126 pub fn current_entry<'b>(&self, book: &'b Book) -> Option<&'b crate::BookEntry> {
127 self.entries_in_cat(book).into_iter().nth(self.entry)
128 }
129
130 pub fn page_count(&self, book: &Book) -> usize {
131 self.current_entry(book)
132 .map(|e| e.pages.len().max(1))
133 .unwrap_or(1)
134 }
135}