1use serde::{Deserialize, Serialize};
2use uuid::Uuid;
3
4use taskers_domain::{
5 AppModel, Direction, PaneId, PaneKind, PaneMetadataPatch, PersistedSession, SignalEvent,
6 SplitAxis, SurfaceId, WindowFrame, WindowId, WorkspaceId, WorkspaceViewport, WorkspaceWindowId,
7};
8
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(tag = "command", rename_all = "snake_case")]
11pub enum ControlCommand {
12 CreateWorkspace {
13 label: String,
14 },
15 RenameWorkspace {
16 workspace_id: WorkspaceId,
17 label: String,
18 },
19 SwitchWorkspace {
20 window_id: Option<WindowId>,
21 workspace_id: WorkspaceId,
22 },
23 SplitPane {
24 workspace_id: WorkspaceId,
25 pane_id: Option<PaneId>,
26 axis: SplitAxis,
27 },
28 CreateWorkspaceWindow {
29 workspace_id: WorkspaceId,
30 direction: Direction,
31 },
32 FocusWorkspaceWindow {
33 workspace_id: WorkspaceId,
34 workspace_window_id: WorkspaceWindowId,
35 },
36 FocusPane {
37 workspace_id: WorkspaceId,
38 pane_id: PaneId,
39 },
40 FocusPaneDirection {
41 workspace_id: WorkspaceId,
42 direction: Direction,
43 },
44 ResizeActiveWindow {
45 workspace_id: WorkspaceId,
46 direction: Direction,
47 amount: i32,
48 },
49 ResizeActivePaneSplit {
50 workspace_id: WorkspaceId,
51 direction: Direction,
52 amount: i32,
53 },
54 SetWorkspaceWindowFrame {
55 workspace_id: WorkspaceId,
56 workspace_window_id: WorkspaceWindowId,
57 frame: WindowFrame,
58 },
59 SetWindowSplitRatio {
60 workspace_id: WorkspaceId,
61 workspace_window_id: WorkspaceWindowId,
62 path: Vec<bool>,
63 ratio: u16,
64 },
65 UpdatePaneMetadata {
66 pane_id: PaneId,
67 patch: PaneMetadataPatch,
68 },
69 UpdateSurfaceMetadata {
70 surface_id: SurfaceId,
71 patch: PaneMetadataPatch,
72 },
73 CreateSurface {
74 workspace_id: WorkspaceId,
75 pane_id: PaneId,
76 kind: PaneKind,
77 },
78 FocusSurface {
79 workspace_id: WorkspaceId,
80 pane_id: PaneId,
81 surface_id: SurfaceId,
82 },
83 MarkSurfaceCompleted {
84 workspace_id: WorkspaceId,
85 pane_id: PaneId,
86 surface_id: SurfaceId,
87 },
88 CloseSurface {
89 workspace_id: WorkspaceId,
90 pane_id: PaneId,
91 surface_id: SurfaceId,
92 },
93 SetWorkspaceViewport {
94 workspace_id: WorkspaceId,
95 viewport: WorkspaceViewport,
96 },
97 ClosePane {
98 workspace_id: WorkspaceId,
99 pane_id: PaneId,
100 },
101 CloseWorkspace {
102 workspace_id: WorkspaceId,
103 },
104 EmitSignal {
105 workspace_id: WorkspaceId,
106 pane_id: PaneId,
107 surface_id: Option<SurfaceId>,
108 event: SignalEvent,
109 },
110 QueryStatus {
111 query: ControlQuery,
112 },
113}
114
115#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
116#[serde(tag = "scope", rename_all = "snake_case")]
117pub enum ControlQuery {
118 ActiveWindow,
119 Window { window_id: WindowId },
120 Workspace { workspace_id: WorkspaceId },
121 All,
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
125#[serde(tag = "status", rename_all = "snake_case")]
126pub enum ControlResponse {
127 Ack {
128 message: String,
129 },
130 WorkspaceCreated {
131 workspace_id: WorkspaceId,
132 },
133 PaneSplit {
134 pane_id: PaneId,
135 },
136 SurfaceCreated {
137 surface_id: SurfaceId,
138 },
139 WorkspaceWindowCreated {
140 pane_id: PaneId,
141 },
142 Status {
143 session: PersistedSession,
144 },
145 WorkspaceState {
146 workspace_id: WorkspaceId,
147 session: PersistedSession,
148 },
149}
150
151#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
152pub struct RequestFrame {
153 pub request_id: Uuid,
154 pub command: ControlCommand,
155}
156
157#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
158pub struct ResponseFrame {
159 pub request_id: Uuid,
160 pub response: Result<ControlResponse, String>,
161}
162
163impl RequestFrame {
164 pub fn new(command: ControlCommand) -> Self {
165 Self {
166 request_id: Uuid::now_v7(),
167 command,
168 }
169 }
170}
171
172impl From<AppModel> for ControlResponse {
173 fn from(model: AppModel) -> Self {
174 Self::Status {
175 session: model.snapshot(),
176 }
177 }
178}