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 if i < book.categories.len() {
42 let changed = self.at_home || i != self.cat;
43 self.cat = i;
44 self.entry = 0;
45 self.page = 0;
46 self.list_spread = 0;
47 self.at_home = false;
48 return changed;
49 }
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" {
77 if self.list_spread + 1 < self.list_spread_count(book) {
78 self.list_spread += 1;
79 return true;
80 }
81 }
82 false
83 }
84
85 pub fn entries_in_cat<'b>(&self, book: &'b Book) -> Vec<&'b crate::BookEntry> {
87 let cat_id = book
88 .categories
89 .get(self.cat)
90 .map(|c| c.id.as_str())
91 .unwrap_or("");
92 book.entries
93 .iter()
94 .filter(|e| e.category == cat_id)
95 .collect()
96 }
97
98 pub fn list_spread_count(&self, book: &Book) -> usize {
100 let total = self.entries_in_cat(book).len();
101 if total <= ENTRIES_FIRST {
102 return 1;
103 }
104 1 + (total - ENTRIES_FIRST + ENTRIES_PER - 1) / ENTRIES_PER
105 }
106
107 pub fn list_spread_start(&self) -> usize {
109 if self.list_spread == 0 {
110 0
111 } else {
112 ENTRIES_FIRST + (self.list_spread - 1) * ENTRIES_PER
113 }
114 }
115
116 pub fn entries_visible<'b>(&self, book: &'b Book) -> Vec<&'b crate::BookEntry> {
118 let all = self.entries_in_cat(book);
119 let start = self.list_spread_start();
120 let count = if self.list_spread == 0 {
121 ENTRIES_FIRST
122 } else {
123 ENTRIES_PER
124 };
125 all.into_iter().skip(start).take(count).collect()
126 }
127
128 pub fn current_entry<'b>(&self, book: &'b Book) -> Option<&'b crate::BookEntry> {
129 self.entries_in_cat(book).into_iter().nth(self.entry)
130 }
131
132 pub fn page_count(&self, book: &Book) -> usize {
133 self.current_entry(book)
134 .map(|e| e.pages.len().max(1))
135 .unwrap_or(1)
136 }
137}