Skip to content

Commit 364d7c9

Browse files
committed
basic textbox
1 parent 650f537 commit 364d7c9

File tree

5 files changed

+300
-48
lines changed

5 files changed

+300
-48
lines changed

lib/features/workspace/providers/workspace_provider.dart

Lines changed: 101 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import 'package:cookethflow/features/models/canvas_models/objects/triangle_objec
1919
import 'package:cookethflow/features/models/canvas_models/user_cursor.dart';
2020
import 'package:cookethflow/features/models/workspace_model.dart';
2121
import 'package:flutter/material.dart';
22+
import 'package:flutter_quill/flutter_quill.dart';
2223
import 'package:supabase_flutter/supabase_flutter.dart';
2324
import 'package:uuid/uuid.dart';
2425

@@ -52,10 +53,10 @@ class WorkspaceProvider extends StateHandler {
5253
static const double _defaultShapeSize = 100.0; // In canvas units
5354
static const double _handleRadius = 8.0; // In canvas units
5455
Color _currentWorkspaceColor = scaffoldColor;
55-
5656
TextEditingController _workspaceNameController = TextEditingController(
5757
text: 'Workspace Name',
5858
);
59+
QuillController _quillController = QuillController.basic();
5960

6061
bool get isLoading => _isLoading;
6162
bool get isDrawerOpen => _isDrawerOpen;
@@ -77,6 +78,7 @@ class WorkspaceProvider extends StateHandler {
7778
SupabaseService get supabaseService => _supabaseService;
7879

7980
bool get hasSelectedTile => _selectedTileIndex != null;
81+
QuillController get quillController => _quillController;
8082

8183
// --- Core Methods ---
8284

@@ -99,7 +101,9 @@ class WorkspaceProvider extends StateHandler {
99101
_currentlySelectedObjectId = null; // Clear selected object
100102

101103
await _fetchCanvasObjects(); // Fetch objects for the new workspace
102-
_setupRealtimeChannel(_currentWorkspace!.id); // Set up realtime for new workspace
104+
_setupRealtimeChannel(
105+
_currentWorkspace!.id,
106+
); // Set up realtime for new workspace
103107

104108
notifyListeners();
105109
}
@@ -134,41 +138,49 @@ class WorkspaceProvider extends StateHandler {
134138
void _setupRealtimeChannel(String workspaceId) {
135139
// Only subscribe if not already subscribed to this workspace
136140
if (_canvasChannel?.topic != Constants.channelName + ':$workspaceId') {
137-
_canvasChannel = _supabaseService.supabase
138-
.channel(Constants.channelName + ':$workspaceId') // Unique channel per workspace
139-
.onBroadcast(
140-
event: Constants.broadcastEventName,
141-
callback: (payload) {
142-
// Only process broadcasts if they belong to the current workspace
143-
if (payload['workspace_id'] == _currentWorkspace?.id) {
144-
final cursor = UserCursor.fromJson(payload['cursor']);
145-
_userCursors[cursor.id] = cursor;
146-
147-
if (payload['object'] != null) {
148-
final object = CanvasObject.fromJson(payload['object']);
149-
_canvasObjects[object.id] = object;
150-
}
151-
notifyListeners();
152-
}
153-
},
154-
)
155-
.subscribe();
141+
_canvasChannel =
142+
_supabaseService.supabase
143+
.channel(
144+
Constants.channelName + ':$workspaceId',
145+
) // Unique channel per workspace
146+
.onBroadcast(
147+
event: Constants.broadcastEventName,
148+
callback: (payload) {
149+
// Only process broadcasts if they belong to the current workspace
150+
if (payload['workspace_id'] == _currentWorkspace?.id) {
151+
final cursor = UserCursor.fromJson(payload['cursor']);
152+
_userCursors[cursor.id] = cursor;
153+
154+
if (payload['object'] != null) {
155+
final object = CanvasObject.fromJson(payload['object']);
156+
_canvasObjects[object.id] = object;
157+
}
158+
notifyListeners();
159+
}
160+
},
161+
)
162+
.subscribe();
156163
}
157164
}
158165

159166
// --- Realtime Sync ---
160167
// Now expects canvas coordinates for cursorPosition
161168
Future<void> syncCanvasObject(Offset cursorPosition) {
162169
final myCursor = UserCursor(position: cursorPosition, id: _myId);
163-
if (_currentWorkspace == null || _canvasChannel == null) return Future.value();
170+
if (_currentWorkspace == null || _canvasChannel == null)
171+
return Future.value();
164172

165173
return _canvasChannel!.sendBroadcastMessage(
166174
event: Constants.broadcastEventName,
167175
payload: {
168176
'cursor': myCursor.toJson(),
169-
if (_currentlySelectedObjectId != null && _canvasObjects.containsKey(_currentlySelectedObjectId!)) // Ensure object exists
177+
if (_currentlySelectedObjectId != null &&
178+
_canvasObjects.containsKey(
179+
_currentlySelectedObjectId!,
180+
)) // Ensure object exists
170181
'object': _canvasObjects[_currentlySelectedObjectId!]!.toJson(),
171-
'workspace_id': _currentWorkspace!.id, // Include workspace_id in broadcast
182+
'workspace_id':
183+
_currentWorkspace!.id, // Include workspace_id in broadcast
172184
},
173185
);
174186
}
@@ -178,8 +190,11 @@ class WorkspaceProvider extends StateHandler {
178190
// Debounce this if it causes too many updates on every key stroke
179191
// For simplicity, we'll directly update on change for now.
180192
// A better approach for frequent changes is to use a debounce timer.
181-
if (_currentWorkspace != null && _currentWorkspace!.name != _workspaceNameController.text) {
182-
_currentWorkspace = _currentWorkspace!.copyWith(name: _workspaceNameController.text);
193+
if (_currentWorkspace != null &&
194+
_currentWorkspace!.name != _workspaceNameController.text) {
195+
_currentWorkspace = _currentWorkspace!.copyWith(
196+
name: _workspaceNameController.text,
197+
);
183198
_updateWorkspaceNameInDb(_workspaceNameController.text);
184199
}
185200
}
@@ -209,7 +224,9 @@ class WorkspaceProvider extends StateHandler {
209224
// Save the current object state to the database
210225
await _supabaseService.supabase.from('canvas_objects').upsert({
211226
'id': drawnObjectId,
212-
'object': _canvasObjects[drawnObjectId]!.toJson(), // Ensure this toJson() matches your DB schema (jsonb)
227+
'object':
228+
_canvasObjects[drawnObjectId]!
229+
.toJson(), // Ensure this toJson() matches your DB schema (jsonb)
213230
'workspace_id': _currentWorkspace!.id,
214231
});
215232
print('Canvas object ${drawnObjectId} upserted to DB.');
@@ -290,18 +307,26 @@ class WorkspaceProvider extends StateHandler {
290307
}
291308

292309
// Expects details.globalPosition to be in canvas coordinates
293-
void addNewNode(DragDownDetails details) async { // Make async to save immediately
310+
void addNewNode(DragDownDetails details) async {
311+
// Make async to save immediately
294312
if (_currentWorkspace == null) {
295313
print("Cannot add node: No workspace selected.");
296314
return;
297315
}
298316
CanvasObject? newObject;
299-
final defaultTopLeft = details.globalPosition - const Offset(_defaultShapeSize / 2, _defaultShapeSize / 2);
300-
final defaultBottomRight = details.globalPosition + const Offset(_defaultShapeSize / 2, _defaultShapeSize / 2);
317+
final defaultTopLeft =
318+
details.globalPosition -
319+
const Offset(_defaultShapeSize / 2, _defaultShapeSize / 2);
320+
final defaultBottomRight =
321+
details.globalPosition +
322+
const Offset(_defaultShapeSize / 2, _defaultShapeSize / 2);
301323

302324
switch (_currentMode) {
303325
case DrawMode.circle:
304-
newObject = Circle.createNew(details.globalPosition, _defaultShapeSize / 2);
326+
newObject = Circle.createNew(
327+
details.globalPosition,
328+
_defaultShapeSize / 2,
329+
);
305330
break;
306331
case DrawMode.rectangle:
307332
newObject = Rectangle.createNew(defaultTopLeft, defaultBottomRight);
@@ -325,7 +350,10 @@ class WorkspaceProvider extends StateHandler {
325350
newObject = Triangle.createNew(defaultTopLeft, defaultBottomRight);
326351
break;
327352
case DrawMode.invertedTriangle:
328-
newObject = InvertedTriangle.createNew(defaultTopLeft, defaultBottomRight);
353+
newObject = InvertedTriangle.createNew(
354+
defaultTopLeft,
355+
defaultBottomRight,
356+
);
329357
break;
330358
case DrawMode.pointer:
331359
break;
@@ -334,7 +362,8 @@ class WorkspaceProvider extends StateHandler {
334362
if (newObject != null) {
335363
_canvasObjects[newObject.id] = newObject;
336364
_currentlySelectedObjectId = newObject.id;
337-
_interactionMode = InteractionMode.moving; // Set to moving immediately after creation
365+
_interactionMode =
366+
InteractionMode.moving; // Set to moving immediately after creation
338367
notifyListeners();
339368

340369
// Immediately save the newly created object to the database
@@ -353,8 +382,10 @@ class WorkspaceProvider extends StateHandler {
353382

354383
// Expects details.globalPosition and details.delta to be in canvas coordinates
355384
void onPanDown(DragDownDetails details) {
356-
_cursorPosition = details.globalPosition; // This is now in canvas coordinates
357-
_panStartPoint = details.globalPosition; // This is now in canvas coordinates
385+
_cursorPosition =
386+
details.globalPosition; // This is now in canvas coordinates
387+
_panStartPoint =
388+
details.globalPosition; // This is now in canvas coordinates
358389

359390
_currentlySelectedObjectId = null;
360391
_interactionMode = InteractionMode.none;
@@ -371,17 +402,20 @@ class WorkspaceProvider extends StateHandler {
371402
_interactionMode = InteractionMode.resizingTopLeft;
372403
notifyListeners();
373404
return; // Exit after finding a handle
374-
} else if ((details.globalPosition - rect.topRight).distance < _handleRadius) {
405+
} else if ((details.globalPosition - rect.topRight).distance <
406+
_handleRadius) {
375407
_currentlySelectedObjectId = canvasObject.id;
376408
_interactionMode = InteractionMode.resizingTopRight;
377409
notifyListeners();
378410
return;
379-
} else if ((details.globalPosition - rect.bottomLeft).distance < _handleRadius) {
411+
} else if ((details.globalPosition - rect.bottomLeft).distance <
412+
_handleRadius) {
380413
_currentlySelectedObjectId = canvasObject.id;
381414
_interactionMode = InteractionMode.resizingBottomLeft;
382415
notifyListeners();
383416
return;
384-
} else if ((details.globalPosition - rect.bottomRight).distance < _handleRadius) {
417+
} else if ((details.globalPosition - rect.bottomRight).distance <
418+
_handleRadius) {
385419
_currentlySelectedObjectId = canvasObject.id;
386420
_interactionMode = InteractionMode.resizingBottomRight;
387421
notifyListeners();
@@ -391,7 +425,8 @@ class WorkspaceProvider extends StateHandler {
391425

392426
// If no handle interaction, check if we're clicking on an object to move it
393427
for (final canvasObject in _canvasObjects.values.toList().reversed) {
394-
if (canvasObject.intersectsWith(details.globalPosition)) { // details.globalPosition is now canvas coordinate
428+
if (canvasObject.intersectsWith(details.globalPosition)) {
429+
// details.globalPosition is now canvas coordinate
395430
_currentlySelectedObjectId = canvasObject.id;
396431
_interactionMode = InteractionMode.moving;
397432
notifyListeners();
@@ -405,31 +440,49 @@ class WorkspaceProvider extends StateHandler {
405440

406441
// Expects details.globalPosition and details.delta to be in canvas coordinates
407442
void onPanUpdate(DragUpdateDetails details) {
408-
_cursorPosition = details.globalPosition; // This is now in canvas coordinates
443+
_cursorPosition =
444+
details.globalPosition; // This is now in canvas coordinates
409445
if (_currentlySelectedObjectId == null) return;
410446

411447
final currentObject = _canvasObjects[_currentlySelectedObjectId!];
412448
if (currentObject == null) return;
413449

414450
switch (_interactionMode) {
415451
case InteractionMode.moving:
416-
_canvasObjects[_currentlySelectedObjectId!] = currentObject.move(details.delta); // delta is already in canvas units
452+
_canvasObjects[_currentlySelectedObjectId!] = currentObject.move(
453+
details.delta,
454+
); // delta is already in canvas units
417455
break;
418456
case InteractionMode.resizingTopLeft:
419457
final newTopLeft = currentObject.getBounds().topLeft + details.delta;
420-
_canvasObjects[_currentlySelectedObjectId!] = (currentObject as dynamic).resize(newTopLeft, currentObject.getBounds().bottomRight);
458+
_canvasObjects[_currentlySelectedObjectId!] = (currentObject as dynamic)
459+
.resize(newTopLeft, currentObject.getBounds().bottomRight);
421460
break;
422461
case InteractionMode.resizingTopRight:
423462
final newTopRight = currentObject.getBounds().topRight + details.delta;
424-
_canvasObjects[_currentlySelectedObjectId!] = (currentObject as dynamic).resize(Offset(currentObject.getBounds().topLeft.dx, newTopRight.dy), Offset(newTopRight.dx, currentObject.getBounds().bottomRight.dy));
463+
_canvasObjects[_currentlySelectedObjectId!] = (currentObject as dynamic)
464+
.resize(
465+
Offset(currentObject.getBounds().topLeft.dx, newTopRight.dy),
466+
Offset(newTopRight.dx, currentObject.getBounds().bottomRight.dy),
467+
);
425468
break;
426469
case InteractionMode.resizingBottomLeft:
427-
final newBottomLeft = currentObject.getBounds().bottomLeft + details.delta;
428-
_canvasObjects[_currentlySelectedObjectId!] = (currentObject as dynamic).resize(Offset(newBottomLeft.dx, currentObject.getBounds().topLeft.dy), Offset(currentObject.getBounds().bottomRight.dx, newBottomLeft.dy));
470+
final newBottomLeft =
471+
currentObject.getBounds().bottomLeft + details.delta;
472+
_canvasObjects[_currentlySelectedObjectId!] = (currentObject as dynamic)
473+
.resize(
474+
Offset(newBottomLeft.dx, currentObject.getBounds().topLeft.dy),
475+
Offset(
476+
currentObject.getBounds().bottomRight.dx,
477+
newBottomLeft.dy,
478+
),
479+
);
429480
break;
430481
case InteractionMode.resizingBottomRight:
431-
final newBottomRight = currentObject.getBounds().bottomRight + details.delta;
432-
_canvasObjects[_currentlySelectedObjectId!] = (currentObject as dynamic).resize(currentObject.getBounds().topLeft, newBottomRight);
482+
final newBottomRight =
483+
currentObject.getBounds().bottomRight + details.delta;
484+
_canvasObjects[_currentlySelectedObjectId!] = (currentObject as dynamic)
485+
.resize(currentObject.getBounds().topLeft, newBottomRight);
433486
break;
434487
case InteractionMode.none:
435488
break;
@@ -457,4 +510,4 @@ class WorkspaceProvider extends StateHandler {
457510
_canvasChannel?.unsubscribe();
458511
super.dispose();
459512
}
460-
}
513+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import 'package:cookethflow/features/workspace/providers/canvas_provider.dart';
2+
import 'package:cookethflow/features/workspace/providers/workspace_provider.dart';
3+
import 'package:flutter/material.dart';
4+
import 'package:flutter_quill/flutter_quill.dart';
5+
import 'package:flutter_screenutil/flutter_screenutil.dart';
6+
import 'package:provider/provider.dart';
7+
8+
class TextBox extends StatelessWidget {
9+
const TextBox({super.key});
10+
11+
@override
12+
Widget build(BuildContext context) {
13+
return Consumer2<WorkspaceProvider, CanvasProvider>(
14+
builder: (context, workspaceProvider, canvasProvider, child) {
15+
return SingleChildScrollView(child: Container(
16+
height: 100.h,
17+
width: 600.w,
18+
child: QuillSimpleToolbar(controller: workspaceProvider.quillController),
19+
));
20+
}
21+
);
22+
}
23+
}

macos/Flutter/GeneratedPluginRegistrant.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import app_links
99
import file_selector_macos
1010
import google_sign_in_ios
1111
import path_provider_foundation
12+
import quill_native_bridge_macos
1213
import shared_preferences_foundation
1314
import sqflite_darwin
1415
import url_launcher_macos
@@ -18,6 +19,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
1819
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
1920
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
2021
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
22+
QuillNativeBridgePlugin.register(with: registry.registrar(forPlugin: "QuillNativeBridgePlugin"))
2123
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
2224
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
2325
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))

0 commit comments

Comments
 (0)