Skip to content

Commit 431d704

Browse files
committed
fix: node de-selected on clicking anywhere on workspace
1 parent feeaff4 commit 431d704

File tree

2 files changed

+64
-88
lines changed

2 files changed

+64
-88
lines changed

lib/providers/workspace_provider.dart

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,15 @@ class WorkspaceProvider extends StateHandler {
260260
}
261261
}
262262

263+
void deselectAllNodes() {
264+
if (hasSelectedNode) {
265+
_nodeList.forEach((key, node) {
266+
node.isSelected = false;
267+
});
268+
notifyListeners();
269+
}
270+
}
271+
263272
bool displayToolbox() {
264273
if (selectedNode != null && selectedNode!.isSelected) {
265274
notifyListeners();
@@ -432,14 +441,12 @@ class WorkspaceProvider extends StateHandler {
432441

433442
Future<void> exportWorkspace({required ExportType exportType}) async {
434443
try {
435-
// Sanitize workspace name
436444
String safeName = flowManager.flowName
437445
.replaceAll(RegExp(r'[^\w\s-]'), '')
438446
.replaceAll(RegExp(r'\s+'), '_');
439447

440448
if (safeName.isEmpty) safeName = "workspace";
441449

442-
// Include timestamp in file name
443450
final timestamp = DateTime.now().millisecondsSinceEpoch;
444451
String fileName = "${safeName}_$timestamp";
445452

lib/screens/workspace_screens/workspace.dart

Lines changed: 55 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ class Workspace extends StatefulWidget {
2525
}
2626

2727
class _WorkspaceState extends State<Workspace> {
28-
// bool _isPanning = false;
29-
3028
@override
3129
void initState() {
3230
super.initState();
@@ -48,48 +46,38 @@ class _WorkspaceState extends State<Workspace> {
4846
final screenSize = MediaQuery.of(context).size;
4947

5048
// Calculate the initial offset to center the view
51-
// Canvas size is 100000x100000, so center is (50000, 50000)
52-
// Adjust the offset to center it relative to the screen size
5349
final double centerX = (canvasDimension / 2) - (screenSize.width / 2);
5450
final double centerY = (canvasDimension / 2) - (screenSize.height / 2);
5551

5652
// Set the initial transformation matrix to center the view
5753
Matrix4 matrix = Matrix4.identity()
58-
..translate(-centerX,
59-
-centerY); // Negative because we move the canvas opposite to center it
54+
..translate(-centerX, -centerY);
6055

6156
workspaceProvider.transformationController.value = matrix;
6257

6358
// Sync initial state with provider
6459
workspaceProvider.updatePosition(Offset(-centerX, -centerY));
65-
workspaceProvider.updateScale(1.0); // Default scale
60+
workspaceProvider.updateScale(1.0);
6661
workspaceProvider.updateFlowManager();
6762

6863
workspaceProvider.setInitialize(true);
6964
}
7065

71-
// Connect the transformation controller to the workspace provider
7266
void _syncWithProvider() {
7367
final workspaceProvider =
7468
Provider.of<WorkspaceProvider>(context, listen: false);
7569

76-
// Extract matrix values
7770
final Matrix4 matrix = workspaceProvider.transformationController.value;
7871

79-
// Extract scale (using proper mathematical approach to extract scale)
8072
final double scaleX = math.sqrt(
8173
matrix.getColumn(0)[0] * matrix.getColumn(0)[0] +
8274
matrix.getColumn(0)[1] * matrix.getColumn(0)[1]);
8375

84-
// Extract translation
8576
final Offset offset =
8677
Offset(matrix.getTranslation().x, matrix.getTranslation().y);
8778

88-
// Update provider values
8979
workspaceProvider.updateScale(scaleX);
9080
workspaceProvider.updatePosition(offset);
91-
92-
// Update flow manager to persist zoom/pan state
9381
workspaceProvider.updateFlowManager();
9482
}
9583

@@ -105,7 +93,6 @@ class _WorkspaceState extends State<Workspace> {
10593
);
10694
}
10795

108-
// bool _isPanning = workProvider.isPanning;
10996
return Scaffold(
11097
appBar: PreferredSize(
11198
preferredSize: const Size.fromHeight(80),
@@ -204,27 +191,22 @@ class _WorkspaceState extends State<Workspace> {
204191
backgroundColor: white,
205192
body: Stack(
206193
children: [
207-
// The infinite canvas
208194
RepaintBoundary(
209195
key: workProvider.repaintBoundaryKey,
210196
child: InteractiveViewer(
211197
transformationController:
212198
workProvider.transformationController,
213-
minScale: 0.1, // Allow zoom out to 10%
199+
minScale: 0.1,
214200
maxScale: 5.0,
215-
constrained:
216-
false, // This is critical - don't constrain the canvas
217-
boundaryMargin:
218-
EdgeInsets.all(double.infinity), // Allow infinite panning
201+
constrained: false,
202+
boundaryMargin: EdgeInsets.all(double.infinity),
219203
onInteractionStart: (details) {
220204
workProvider.updatePanning(true);
221205
},
222206
onInteractionUpdate: (details) {
223-
// Update provider with current scale and position for node dragging calculations
224207
final Matrix4 matrix =
225208
workProvider.transformationController.value;
226209

227-
// Extract scale from the transformation matrixF
228210
final scaleX = math.sqrt(
229211
matrix.getColumn(0)[0] * matrix.getColumn(0)[0] +
230212
matrix.getColumn(0)[1] * matrix.getColumn(0)[1]);
@@ -236,70 +218,64 @@ class _WorkspaceState extends State<Workspace> {
236218
workProvider.updatePosition(translation);
237219
},
238220
onInteractionEnd: (details) {
239-
// Sync final state with provider
240221
_syncWithProvider();
241222
workProvider.updatePanning(false);
242223
},
243-
child: SizedBox(
244-
// Huge size for effectively infinite canvas
245-
width: canvasDimension,
246-
height: canvasDimension,
247-
child: Stack(
248-
children: [
249-
// Background grid for better visual orientation
250-
Positioned.fill(
251-
child: CustomPaint(
252-
painter: GridPainter(),
253-
),
254-
),
255-
256-
// Draw connections
257-
...workProvider.connections.map((connection) {
258-
return CustomPaint(
259-
size: Size.infinite,
260-
painter: LinePainter(
261-
start: workProvider
262-
.nodeList[connection.sourceNodeId]!.position,
263-
end: workProvider
264-
.nodeList[connection.targetNodeId]!.position,
265-
sourceNodeId: connection.sourceNodeId,
266-
startPoint: connection.sourcePoint,
267-
targetNodeId: connection.targetNodeId,
268-
endPoint: connection.targetPoint,
269-
scale: workProvider.scale,
270-
connection: connection,
271-
),
272-
);
273-
}),
274-
275-
// Draw nodes
276-
...workProvider.nodeList.entries.map((entry) {
277-
var id = entry.key;
278-
var node = entry.value;
279-
return Positioned(
280-
left: node.position.dx,
281-
top: node.position.dy,
282-
child: Node(
283-
id: id,
284-
type: node.type,
285-
onResize: (Size newSize) =>
286-
workProvider.onResize(id, newSize),
287-
onDrag: (offset) =>
288-
workProvider.dragNode(id, offset),
289-
// position: node.position,
224+
child: GestureDetector(
225+
behavior: HitTestBehavior.opaque,
226+
onTap: () {
227+
workProvider.deselectAllNodes();
228+
},
229+
child: SizedBox(
230+
width: canvasDimension,
231+
height: canvasDimension,
232+
child: Stack(
233+
children: [
234+
Positioned.fill(
235+
child: CustomPaint(
236+
painter: GridPainter(),
290237
),
291-
);
292-
}),
293-
],
238+
),
239+
...workProvider.connections.map((connection) {
240+
return CustomPaint(
241+
size: Size.infinite,
242+
painter: LinePainter(
243+
start: workProvider
244+
.nodeList[connection.sourceNodeId]!.position,
245+
end: workProvider
246+
.nodeList[connection.targetNodeId]!.position,
247+
sourceNodeId: connection.sourceNodeId,
248+
startPoint: connection.sourcePoint,
249+
targetNodeId: connection.targetNodeId,
250+
endPoint: connection.targetPoint,
251+
scale: workProvider.scale,
252+
connection: connection,
253+
),
254+
);
255+
}),
256+
...workProvider.nodeList.entries.map((entry) {
257+
var id = entry.key;
258+
var node = entry.value;
259+
return Positioned(
260+
left: node.position.dx,
261+
top: node.position.dy,
262+
child: Node(
263+
id: id,
264+
type: node.type,
265+
onResize: (Size newSize) =>
266+
workProvider.onResize(id, newSize),
267+
onDrag: (offset) =>
268+
workProvider.dragNode(id, offset),
269+
),
270+
);
271+
}),
272+
],
273+
),
294274
),
295275
),
296276
),
297277
),
298-
299-
// UI elements that should stay fixed regardless of zoom/pan
300278
FloatingDrawer(flowId: widget.flowId),
301-
302-
// Toolbar and node editing tools
303279
Positioned(
304280
top: 20,
305281
right: 20,
@@ -322,8 +298,6 @@ class _WorkspaceState extends State<Workspace> {
322298
],
323299
),
324300
),
325-
326-
// Zoom indicator
327301
Positioned(
328302
right: 24,
329303
bottom: 24,
@@ -335,15 +309,10 @@ class _WorkspaceState extends State<Workspace> {
335309
border: Border.all(color: textColor, width: 1),
336310
),
337311
child: Builder(builder: (context) {
338-
// Get the current matrix
339312
final matrix = workProvider.transformationController.value;
340-
341-
// Extract the scale value accurately
342313
final scale = math.sqrt(
343314
matrix.getColumn(0)[0] * matrix.getColumn(0)[0] +
344315
matrix.getColumn(0)[1] * matrix.getColumn(0)[1]);
345-
346-
// Display accurate percentage
347316
return Text(
348317
"${(scale * 100).toInt()}%",
349318
style: TextStyle(
@@ -360,4 +329,4 @@ class _WorkspaceState extends State<Workspace> {
360329
},
361330
);
362331
}
363-
}
332+
}

0 commit comments

Comments
 (0)