1use std::{marker::PhantomData, sync::Arc};
6
7use elgato_streamdeck::AsyncStreamDeck;
8use generic_array::ArrayLength;
9use tokio::sync::{mpsc, RwLock};
10
11use crate::{
12 button::{render_button, RenderConfig},
13 navigation::NavigationEntry,
14 theme::Theme,
15};
16
17use super::{button::ButtonState, matrix::ButtonMatrix, View};
18
19pub struct DisplayManager<N: NavigationEntry<W, H, C>, W, H, C>
24where
25 W: ArrayLength,
26 H: ArrayLength,
27 C: Send + Clone + Sync + 'static,
28{
29 pub(crate) config: RenderConfig,
31 pub(crate) theme: Theme,
33 pub(crate) deck: Arc<AsyncStreamDeck>,
35 pub(crate) view: RwLock<Box<dyn View<W, H, C, N>>>,
37 pub(crate) _navigation: PhantomData<N>,
39 pub(crate) _width: PhantomData<W>,
41 pub(crate) _height: PhantomData<H>,
43 pub(crate) navigation_sender: Arc<mpsc::Sender<N>>,
45 pub(crate) context: C,
47 pub(crate) current_navigation: RwLock<N>,
49}
50
51impl<N: NavigationEntry<W, H, C>, W, H, C> DisplayManager<N, W, H, C>
52where
53 W: ArrayLength,
54 H: ArrayLength,
55 C: Send + Clone + Sync + 'static,
56{
57 pub fn new(
62 deck: Arc<AsyncStreamDeck>,
63 config: RenderConfig,
64 theme: Theme,
65 context: C,
66 ) -> Result<(Self, mpsc::Receiver<N>), Box<dyn std::error::Error>> {
67 let (sender, receiver) = mpsc::channel(1);
68 let sender = Arc::new(sender);
69 Ok((
70 Self {
71 config,
72 theme,
73 deck,
74 view: RwLock::new(N::default().get_view()?),
75 _navigation: PhantomData,
76 _width: PhantomData,
77 _height: PhantomData,
78 navigation_sender: sender.clone(),
79 context,
80 current_navigation: RwLock::new(N::default()),
81 },
82 receiver,
83 ))
84 }
85
86 pub async fn navigate_to(&self, navigation_entry: N) -> Result<(), Box<dyn std::error::Error>> {
91 let mut view = self.view.write().await;
92 let mut current_navigation = self.current_navigation.write().await;
93 *view = navigation_entry.get_view()?;
94 *current_navigation = navigation_entry.clone();
95 Ok(())
96 }
97
98 pub async fn get_current_navigation(
102 &self,
103 ) -> Result<N, Box<dyn std::error::Error>> {
104 let current_navigation = self.current_navigation.read().await;
105 Ok(current_navigation.clone())
106 }
107
108 pub async fn render(&self) -> Result<(), Box<dyn std::error::Error>> {
112 let view = self.view.read().await;
113 let button_matrix = view.render().await?;
114 self.render_matrix(&button_matrix).await?;
115 Ok(())
116 }
117
118 pub async fn fetch_all(&self) -> Result<(), Box<dyn std::error::Error>> {
122 let view = self.view.read().await;
123 let result = view.fetch_all(&self.context).await;
124 if let Err(e) = result {
125 eprintln!("Error fetching view state: {}", e);
126 }
127 Ok(())
128 }
129
130 async fn render_matrix(
134 &self,
135 button_matrix: &ButtonMatrix<W, H>,
136 ) -> Result<(), Box<dyn std::error::Error>> {
137 for x in 0..W::to_usize() {
138 for y in 0..H::to_usize() {
139 let button = &button_matrix.buttons[y][x];
140 let button_index = (y * W::to_usize() + x) as u8;
141 let background_color = match button.state {
142 ButtonState::Default => self.theme.background,
143 ButtonState::Active => self.theme.active_background,
144 ButtonState::Inactive => self.theme.inactive_background,
145 ButtonState::Error => self.theme.error_background,
146 ButtonState::Pressed => self.theme.pressed_background,
147 };
148 let foreground_color = match button.state {
149 ButtonState::Default => self.theme.foreground_color,
150 ButtonState::Active => self.theme.active_foreground_color,
151 ButtonState::Inactive => self.theme.foreground_color,
152 ButtonState::Error => self.theme.foreground_color,
153 ButtonState::Pressed => self.theme.active_foreground_color,
154 };
155 let raw_button = match button.icon {
156 Some(icon) => crate::button::Button::IconWithText {
157 svg_data: icon,
158 text: button.text.to_string(),
159 background: background_color,
160 foreground: foreground_color,
161 },
162 None => crate::button::Button::Text {
163 text: button.text.to_string(),
164 background: background_color,
165 foreground: foreground_color,
166 },
167 };
168 let image = render_button(&raw_button, &self.config)?;
169 self.deck.set_button_image(button_index, image).await?;
170 }
171 self.deck.flush().await?;
172 }
173 Ok(())
174 }
175
176 pub async fn on_press(&self, button: u8) -> Result<(), Box<dyn std::error::Error>> {
181 let view = self.view.read().await;
182 let mut button_matrix = view.render().await?;
183 let button_index = button as usize;
184 let button = button_matrix
185 .get_button_by_index(button_index)
186 .ok_or("Button not found")?;
187 let new_button = button.updated_state(ButtonState::Pressed);
188 button_matrix.set_button_by_index(button_index, new_button)?;
189 self.render_matrix(&button_matrix).await?;
190 Ok(())
191 }
192
193 pub async fn on_release(&self, button: u8) -> Result<(), Box<dyn std::error::Error>> {
198 let view = self.view.read().await;
199 let result = view
200 .on_click(&self.context, button, self.navigation_sender.clone())
201 .await;
202 if let Err(e) = result {
203 eprintln!("Error handling button click: {}", e);
204 }
205 self.render().await?;
206 Ok(())
207 }
208}