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}
48
49impl<N: NavigationEntry<W, H, C>, W, H, C> DisplayManager<N, W, H, C>
50where
51 W: ArrayLength,
52 H: ArrayLength,
53 C: Send + Clone + Sync + 'static,
54{
55 pub fn new(
60 deck: Arc<AsyncStreamDeck>,
61 config: RenderConfig,
62 theme: Theme,
63 context: C,
64 ) -> Result<(Self, mpsc::Receiver<N>), Box<dyn std::error::Error>> {
65 let (sender, receiver) = mpsc::channel(1);
66 let sender = Arc::new(sender);
67 Ok((
68 Self {
69 config,
70 theme,
71 deck,
72 view: RwLock::new(N::default().get_view()?),
73 _navigation: PhantomData,
74 _width: PhantomData,
75 _height: PhantomData,
76 navigation_sender: sender.clone(),
77 context,
78 },
79 receiver,
80 ))
81 }
82
83 pub async fn navigate_to(
88 &self,
89 navigation_entry: N,
90 ) -> Result<(), Box<dyn std::error::Error>> {
91 let mut view = self.view.write().await;
92 *view = navigation_entry.get_view()?;
93 Ok(())
94 }
95
96 pub async fn render(&self) -> Result<(), Box<dyn std::error::Error>> {
100 let view = self.view.read().await;
101 let button_matrix = view.render().await?;
102 self.render_matrix(&button_matrix).await?;
103 Ok(())
104 }
105
106 pub async fn fetch_all(&self) -> Result<(), Box<dyn std::error::Error>> {
110 let view = self.view.read().await;
111 let result = view.fetch_all(&self.context).await;
112 if let Err(e) = result {
113 eprintln!("Error fetching view state: {}", e);
114 }
115 Ok(())
116 }
117
118 async fn render_matrix(
122 &self,
123 button_matrix: &ButtonMatrix<W, H>,
124 ) -> Result<(), Box<dyn std::error::Error>> {
125 for x in 0..W::to_usize() {
126 for y in 0..H::to_usize() {
127 let button = &button_matrix.buttons[y][x];
128 let button_index = (y * W::to_usize() + x) as u8;
129 let background_color = match button.state {
130 ButtonState::Default => self.theme.background,
131 ButtonState::Active => self.theme.active_background,
132 ButtonState::Inactive => self.theme.inactive_background,
133 ButtonState::Error => self.theme.error_background,
134 ButtonState::Pressed => self.theme.pressed_background,
135 };
136 let foreground_color = match button.state {
137 ButtonState::Default => self.theme.foreground_color,
138 ButtonState::Active => self.theme.active_foreground_color,
139 ButtonState::Inactive => self.theme.foreground_color,
140 ButtonState::Error => self.theme.foreground_color,
141 ButtonState::Pressed => self.theme.active_foreground_color,
142 };
143 let raw_button = match button.icon {
144 Some(icon) => crate::button::Button::IconWithText {
145 svg_data: icon,
146 text: button.text.to_string(),
147 background: background_color,
148 foreground: foreground_color,
149 },
150 None => crate::button::Button::Text {
151 text: button.text.to_string(),
152 background: background_color,
153 foreground: foreground_color,
154 },
155 };
156 let image = render_button(&raw_button, &self.config)?;
157 self.deck.set_button_image(button_index, image).await?;
158 }
159 self.deck.flush().await?;
160 }
161 Ok(())
162 }
163
164 pub async fn on_press(&self, button: u8) -> Result<(), Box<dyn std::error::Error>> {
169 let view = self.view.read().await;
170 let mut button_matrix = view.render().await?;
171 let button_index = button as usize;
172 let button = button_matrix
173 .get_button_by_index(button_index)
174 .ok_or("Button not found")?;
175 let new_button = button.updated_state(ButtonState::Pressed);
176 button_matrix.set_button_by_index(button_index, new_button)?;
177 self.render_matrix(&button_matrix).await?;
178 Ok(())
179 }
180
181 pub async fn on_release(&self, button: u8) -> Result<(), Box<dyn std::error::Error>> {
186 let view = self.view.read().await;
187 let result = view.on_click(&self.context, button, self.navigation_sender.clone())
188 .await;
189 if let Err(e) = result {
190 eprintln!("Error handling button click: {}", e);
191 }
192 self.render().await?;
193 Ok(())
194 }
195}