1use serde::{Deserialize, Serialize};
4
5use crate::{InputEvent, Scene};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "lowercase")]
10pub enum ConnectionStatus {
11 Connected,
13 Connecting,
15 Offline,
17 Error,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(rename_all = "lowercase")]
24pub enum InteractionMode {
25 Select,
27 Pan,
29 Draw,
31 Voice,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct CanvasState {
38 pub scene: Scene,
40 pub connection: ConnectionStatus,
42 pub mode: InteractionMode,
44 pending_sync: Vec<InputEvent>,
46 pub has_local_changes: bool,
48}
49
50impl CanvasState {
51 #[must_use]
53 pub fn new(width: f32, height: f32) -> Self {
54 Self {
55 scene: Scene::new(width, height),
56 connection: ConnectionStatus::Connecting,
57 mode: InteractionMode::Select,
58 pending_sync: Vec::new(),
59 has_local_changes: false,
60 }
61 }
62
63 pub fn process_event(&mut self, event: &InputEvent) {
65 if self.connection == ConnectionStatus::Offline {
67 self.pending_sync.push(event.clone());
68 }
69
70 match event {
71 InputEvent::Touch(touch) => {
72 if let Some(primary) = touch.primary_touch() {
74 if let Some(element_id) = self.scene.element_at(primary.x, primary.y) {
75 tracing::debug!("Touch on element: {element_id}");
76 }
77 }
78 }
79 InputEvent::Gesture(gesture) => {
80 tracing::debug!("Gesture: {:?}", gesture);
81 }
82 InputEvent::Voice(voice) => {
83 tracing::debug!("Voice command: {}", voice.transcript);
84 }
85 _ => {}
86 }
87
88 self.has_local_changes = true;
89 }
90
91 pub fn set_connection(&mut self, status: ConnectionStatus) {
93 let was_offline = self.connection == ConnectionStatus::Offline;
94 self.connection = status;
95
96 if was_offline && status == ConnectionStatus::Connected {
98 tracing::info!(
99 "Reconnected with {} pending events to sync",
100 self.pending_sync.len()
101 );
102 }
103 }
104
105 #[must_use]
107 pub fn pending_events(&self) -> &[InputEvent] {
108 &self.pending_sync
109 }
110
111 pub fn clear_pending(&mut self) {
113 self.pending_sync.clear();
114 }
115
116 #[must_use]
118 pub fn is_connected(&self) -> bool {
119 self.connection == ConnectionStatus::Connected
120 }
121
122 #[must_use]
124 pub fn connection_status(&self) -> ConnectionStatus {
125 self.connection
126 }
127
128 #[must_use]
130 pub fn can_interact(&self) -> bool {
131 match self.connection {
133 ConnectionStatus::Connected => true,
134 ConnectionStatus::Offline => {
135 matches!(self.mode, InteractionMode::Select | InteractionMode::Pan)
137 }
138 ConnectionStatus::Connecting | ConnectionStatus::Error => false,
139 }
140 }
141}
142
143impl Default for CanvasState {
144 fn default() -> Self {
145 Self::new(800.0, 600.0)
146 }
147}