streamduck_core/modules/
core_module.rs1use std::collections::HashMap;
4use std::sync::Arc;
5use serde::{Deserialize, Serialize};
6use crate::config::PluginConfig;
7use crate::core::button::{Button, Component};
8use crate::core::{check_feature_list_for_feature, CoreHandle};
9use crate::core::manager::CoreManager;
10use crate::modules::components::{ComponentDefinition, map_ui_values, UIFieldType, UIFieldValue, UIValue};
11use crate::modules::{PluginMetadata, SDModule};
12use crate::modules::events::{core_event_to_global, SDCoreEvent, SDGlobalEvent};
13use crate::socket::send_event_to_socket;
14use crate::SocketManager;
15use crate::thread::rendering::{RendererComponent, RendererSettings};
16use crate::thread::rendering::component_values::{get_renderer_component_values, set_renderer_component_values};
17use crate::util::straight_copy;
18use crate::versions::{CORE, MODULE_MANAGER};
19
20pub struct CoreModule {
22 pub(crate) socket_manager: Arc<SocketManager>
23}
24
25#[async_trait]
26impl SDModule for CoreModule {
27 fn name(&self) -> String {
28 "core".to_string()
29 }
30
31 fn components(&self) -> HashMap<String, ComponentDefinition> {
32 let mut map = HashMap::new();
33
34 map.insert("renderer".to_string(), ComponentDefinition {
35 display_name: "Renderer".to_string(),
36 description: "The only thing that makes a button render an image on streamdeck".to_string(),
37 default_looks: Default::default()
38 });
39
40 map
41 }
42
43 async fn add_component(&self, _: CoreHandle, button: &mut Button, name: &str) {
44 match name {
45 "renderer" => {
46 button.insert_component(RendererComponent::default()).ok();
47 }
48 _ => {}
49 }
50 }
51
52 async fn remove_component(&self, _: CoreHandle, button: &mut Button, name: &str) {
53 match name {
54 "renderer" => {
55 button.remove_component::<RendererComponent>();
56 }
57 _ => {}
58 }
59 }
60
61 async fn paste_component(&self, _: CoreHandle, reference_button: &Button, new_button: &mut Button) {
62 straight_copy(reference_button, new_button, RendererComponent::NAME);
63 }
64
65 async fn component_values(&self, core: CoreHandle, button: &Button, name: &str) -> Vec<UIValue> {
66 match name {
67 "renderer" => {
68 get_renderer_component_values(&core, button).await
69 }
70
71 _ => vec![],
72 }
73 }
74
75 async fn set_component_value(&self, core: CoreHandle, button: &mut Button, name: &str, value: Vec<UIValue>) {
76 match name {
77 "renderer" => {
78 set_renderer_component_values(&core, button, value).await
79 }
80
81 _ => {}
82 }
83 }
84
85 fn listening_for(&self) -> Vec<String> {
86 vec![RendererComponent::NAME.to_string()]
87 }
88
89 async fn settings(&self, core_manager: Arc<CoreManager>) -> Vec<UIValue> {
90 let settings: CoreSettings = core_manager.config.get_plugin_settings().await.unwrap_or_default();
91
92 let mut fields = vec![];
93
94 fields.push(
95 UIValue {
96 name: "rendering".to_string(),
97 display_name: "Rendering Settings".to_string(),
98 description: "Settings related to rendering of buttons".to_string(),
99 ty: UIFieldType::Collapsable,
100 value: UIFieldValue::Collapsable({
101 let mut fields = vec![];
102
103 fields.push(
104 UIValue {
105 name: "plugin_blacklist".to_string(),
106 display_name: "Allowed plugins to render".to_string(),
107 description: "Disabled plugins will not appear on buttons".to_string(),
108 ty: UIFieldType::Collapsable,
109 value: UIFieldValue::Collapsable({
110 core_manager.module_manager.get_modules().await
111 .into_values()
112 .filter_map(|x| if check_feature_list_for_feature(&x.metadata().used_features, "rendering") {
113 let name = x.name();
114 Some(UIValue {
115 name: name.clone(),
116 display_name: name.clone(),
117 description: "".to_string(),
118 ty: UIFieldType::Checkbox { disabled: false },
119 value: UIFieldValue::Checkbox(!settings.renderer.plugin_blacklist.contains(&name))
120 })
121 } else { None })
122 .collect()
123 })
124 }
125 );
126
127 fields
128 })
129 }
130 );
131
132 fields
133 }
134
135 async fn set_setting(&self, core_manager: Arc<CoreManager>, value: Vec<UIValue>) {
136 let mut settings: CoreSettings = core_manager.config.get_plugin_settings().await.unwrap_or_default();
137
138 let change_map = map_ui_values(value);
139
140 if let Some(value) = change_map.get("rendering") {
141 if let UIFieldValue::Collapsable(value) = &value.value {
142 let change_map = map_ui_values(value.clone());
143
144 if let Some(value) = change_map.get("plugin_blacklist") {
145 if let UIFieldValue::Collapsable(value) = &value.value {
146 let change_map = map_ui_values(value.clone());
147
148 for (name, value) in change_map {
149 if let UIFieldValue::Checkbox(state) = value.value {
150 if state {
151 settings.renderer.plugin_blacklist.retain(|x| *x != name);
152 } else {
153 settings.renderer.plugin_blacklist.push(name);
154 }
155 }
156 }
157 }
158 }
159 }
160 }
161
162 for device in core_manager.list_added_devices().await.into_values() {
164 device.core.mark_for_redraw().await;
165 }
166
167 core_manager.config.set_plugin_settings(settings).await;
168 }
169
170 async fn global_event(&self, event: SDGlobalEvent) {
171 send_event_to_socket(&self.socket_manager, event).await;
172 }
173
174 async fn event(&self, core: CoreHandle, event: SDCoreEvent) {
175 let global_event = core_event_to_global(event, &core.core.serial_number().await).await;
176 send_event_to_socket(&self.socket_manager, global_event).await;
177 }
178
179 fn metadata(&self) -> PluginMetadata {
180 PluginMetadata::from_literals(
181 "core",
182 "TheJebForge",
183 "Core of the software, provides essential components",
184 "0.1",
185 &[
186 CORE,
187 MODULE_MANAGER
188 ]
189 )
190 }
191}
192
193#[derive(Serialize, Deserialize, Default)]
195pub struct CoreSettings {
196 pub renderer: RendererSettings
198}
199
200impl PluginConfig for CoreSettings {
201 const NAME: &'static str = "core";
202}
203