1use yog_formats::book::Book;
4
5pub mod action;
6
7pub const ENTRIES_FIRST: usize = 10;
9pub const ENTRIES_PER: usize = 12;
11
12#[derive(Debug, Clone)]
13pub struct BookViewState {
14 pub cat: usize,
15 pub entry: usize,
17 pub page: usize,
18 pub at_home: bool,
19 pub list_spread: usize,
21}
22
23impl Default for BookViewState {
24 fn default() -> Self {
25 Self {
26 cat: 0,
27 entry: 0,
28 page: 0,
29 at_home: true,
30 list_spread: 0,
31 }
32 }
33}
34
35impl BookViewState {
36 pub fn handle(&mut self, ev: &str, book: &Book) -> bool {
38 if ev == action::HOME {
39 if !self.at_home {
40 self.at_home = true;
41 return true;
42 }
43 } else if let Some(n) = ev.strip_prefix(action::CATEGORY) {
44 if let Ok(i) = n.parse::<usize>()
45 && i < book.categories.len()
46 {
47 let changed = self.at_home || i != self.cat;
48 self.cat = i;
49 self.entry = 0;
50 self.page = 0;
51 self.list_spread = 0;
52 self.at_home = false;
53 return changed;
54 }
55 } else if let Some(n) = ev.strip_prefix(action::ENTRY) {
56 if let Ok(i) = n.parse::<usize>() {
58 let total = self.entries_in_cat(book).len();
59 if i < total && (i != self.entry || self.page != 0) {
60 self.entry = i;
61 self.page = 0;
62 return true;
63 }
64 }
65 } else if ev == action::PREV_PAGE {
66 if self.page > 0 {
67 self.page -= 1;
68 return true;
69 }
70 } else if ev == action::NEXT_PAGE {
71 if self.page + 1 < self.page_count(book) {
72 self.page += 1;
73 return true;
74 }
75 } else if ev == action::PREV_LIST {
76 if self.list_spread > 0 {
77 self.list_spread -= 1;
78 return true;
79 }
80 } else if ev == action::NEXT_LIST && self.list_spread + 1 < self.list_spread_count(book) {
81 self.list_spread += 1;
82 return true;
83 }
84 false
85 }
86
87 pub fn entries_in_cat<'b>(&self, book: &'b Book) -> Vec<&'b yog_formats::book::BookEntry> {
89 let cat_id = book
90 .categories
91 .get(self.cat)
92 .map(|c| c.id.as_str())
93 .unwrap_or("");
94 book.entries
95 .iter()
96 .filter(|e| e.category == cat_id && crate::shown(e))
97 .collect()
98 }
99
100 pub fn list_spread_count(&self, book: &Book) -> usize {
102 let total = self.entries_in_cat(book).len();
103 if total <= ENTRIES_FIRST {
104 return 1;
105 }
106 1 + (total - ENTRIES_FIRST).div_ceil(ENTRIES_PER)
107 }
108
109 pub fn list_spread_start(&self) -> usize {
111 if self.list_spread == 0 {
112 0
113 } else {
114 ENTRIES_FIRST + (self.list_spread - 1) * ENTRIES_PER
115 }
116 }
117
118 pub fn entries_visible<'b>(&self, book: &'b Book) -> Vec<&'b yog_formats::book::BookEntry> {
120 let all = self.entries_in_cat(book);
121 let start = self.list_spread_start();
122 let count = if self.list_spread == 0 {
123 ENTRIES_FIRST
124 } else {
125 ENTRIES_PER
126 };
127 all.into_iter().skip(start).take(count).collect()
128 }
129
130 pub fn current_entry<'b>(&self, book: &'b Book) -> Option<&'b yog_formats::book::BookEntry> {
131 self.entries_in_cat(book).into_iter().nth(self.entry)
132 }
133
134 pub fn page_count(&self, book: &Book) -> usize {
135 self.current_entry(book)
136 .map(|e| e.pages.len().max(1))
137 .unwrap_or(1)
138 }
139}