From e44e3102bdc3b5bdef1762425b18f75a1daf04d4 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Wed, 21 May 2025 17:08:45 +0530 Subject: [PATCH 1/8] route fixing --- lib/screens/workspace_screens/workspace.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/screens/workspace_screens/workspace.dart b/lib/screens/workspace_screens/workspace.dart index f3516bf..1b61175 100644 --- a/lib/screens/workspace_screens/workspace.dart +++ b/lib/screens/workspace_screens/workspace.dart @@ -136,7 +136,7 @@ class _WorkspaceState extends State { child: IconButton( padding: const EdgeInsets.only(left: 16.0), icon: const Icon(Icons.arrow_back, color: textColor), - onPressed: () => context.push(RoutesPath.dashboard), + onPressed: () => context.pushReplacement(RoutesPath.dashboard), ), ), actions: [ From feeaff4e3e709bc0e2c386877f71e4a541e77552 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Wed, 21 May 2025 17:25:52 +0530 Subject: [PATCH 2/8] fix: png,svg,json file issue fixed --- lib/core/services/file_services.dart | 219 ++++++++++++------- lib/core/services/platform_file_service.dart | 56 +++-- lib/providers/workspace_provider.dart | 41 ++-- pubspec.lock | 32 +++ pubspec.yaml | 1 + 5 files changed, 229 insertions(+), 120 deletions(-) diff --git a/lib/core/services/file_services.dart b/lib/core/services/file_services.dart index 5032583..0d68802 100644 --- a/lib/core/services/file_services.dart +++ b/lib/core/services/file_services.dart @@ -2,6 +2,8 @@ import 'dart:convert'; import 'dart:typed_data'; import 'package:file_selector_platform_interface/file_selector_platform_interface.dart'; import 'package:cookethflow/core/services/platform_file_service.dart'; +import 'package:flutter/foundation.dart'; +import 'package:universal_html/html.dart' as html; class FileServices { final FileSelectorPlatform fileSelector = FileSelectorPlatform.instance; @@ -11,38 +13,51 @@ class FileServices { required String jsonString, }) async { try { - const XTypeGroup typeGroup = XTypeGroup( - label: 'JSON', - extensions: ['json'], - mimeTypes: ['application/json'], - ); - // Ensure the default name ends with .json - if (!defaultName.toLowerCase().endsWith('.json')) { - defaultName = '$defaultName.json'; - } - - final String? path = await fileSelector.getSavePath( - acceptedTypeGroups: [typeGroup], - suggestedName: defaultName, - ); - - if (path == null) { - return 'Save operation cancelled'; + final sanitizedName = defaultName.toLowerCase().endsWith('.json') + ? defaultName + : '$defaultName.json'; + + if (kIsWeb) { + // Web: Use browser download API + final bytes = Uint8List.fromList(utf8.encode(jsonString)); + final blob = html.Blob([bytes], 'application/json'); + final url = html.Url.createObjectUrlFromBlob(blob); + final anchor = html.AnchorElement(href: url) + ..setAttribute('download', sanitizedName) + ..click(); + html.Url.revokeObjectUrl(url); + return 'success'; + } else { + // Desktop: Use file_selector + const XTypeGroup typeGroup = XTypeGroup( + label: 'JSON', + extensions: ['json'], + mimeTypes: ['application/json'], + ); + + final String? path = await fileSelector.getSavePath( + acceptedTypeGroups: [typeGroup], + suggestedName: sanitizedName, + ); + + if (path == null) { + return 'Save operation cancelled'; + } + + // Ensure the selected path ends with .json + final String savePath = + path.toLowerCase().endsWith('.json') ? path : '$path.json'; + + final XFile file = XFile.fromData( + Uint8List.fromList(utf8.encode(jsonString)), + mimeType: 'application/json', + name: savePath.split('/').last, + ); + + await file.saveTo(savePath); + return 'success'; } - - // Ensure the selected path ends with .json - final String savePath = - path.toLowerCase().endsWith('.json') ? path : '$path.json'; - - final XFile file = XFile.fromData( - Uint8List.fromList(utf8.encode(jsonString)), - mimeType: 'application/json', - name: savePath.split('/').last, - ); - - await file.saveTo(savePath); - return 'success'; } catch (e) { return e.toString(); } @@ -53,30 +68,50 @@ class FileServices { required Uint8List pngBytes, }) async { try { - const XTypeGroup typeGroup = XTypeGroup( - label: 'PNG Images', - extensions: ['png'], - mimeTypes: ['image/png'], - ); - - final String? path = await fileSelector.getSavePath( - acceptedTypeGroups: [typeGroup], - suggestedName: defaultName, - ); - - if (path == null) { - return 'Save operation cancelled'; + // Ensure the default name ends with .png + final sanitizedName = defaultName.toLowerCase().endsWith('.png') + ? defaultName + : '$defaultName.png'; + + if (kIsWeb) { + // Web: Use browser download API + final blob = html.Blob([pngBytes], 'image/png'); + final url = html.Url.createObjectUrlFromBlob(blob); + final anchor = html.AnchorElement(href: url) + ..setAttribute('download', sanitizedName) + ..click(); + html.Url.revokeObjectUrl(url); + return 'success'; + } else { + // Desktop: Use file_selector + const XTypeGroup typeGroup = XTypeGroup( + label: 'PNG Images', + extensions: ['png'], + mimeTypes: ['image/png'], + ); + + final String? path = await fileSelector.getSavePath( + acceptedTypeGroups: [typeGroup], + suggestedName: sanitizedName, + ); + + if (path == null) { + return 'Save operation cancelled'; + } + + // Ensure the selected path ends with .png + final String savePath = + path.toLowerCase().endsWith('.png') ? path : '$path.png'; + + final XFile file = XFile.fromData( + pngBytes, + mimeType: 'image/png', + name: savePath.split('/').last, + ); + + await file.saveTo(savePath); + return 'success'; } - - final XFile file = XFile.fromData( - pngBytes, - mimeType: 'image/png', - name: path.split('/').last, - path: path, - ); - - await file.saveTo(path); - return 'success'; } catch (e) { return e.toString(); } @@ -87,30 +122,51 @@ class FileServices { required String svgString, }) async { try { - const XTypeGroup typeGroup = XTypeGroup( - label: 'SVG Images', - extensions: ['svg'], - mimeTypes: ['image/svg+xml'], - ); - - final String? path = await fileSelector.getSavePath( - acceptedTypeGroups: [typeGroup], - suggestedName: defaultName, - ); - - if (path == null) { - return 'Save operation cancelled'; + // Ensure the default name ends with .svg + final sanitizedName = defaultName.toLowerCase().endsWith('.svg') + ? defaultName + : '$defaultName.svg'; + + if (kIsWeb) { + // Web: Use browser download API + final bytes = Uint8List.fromList(utf8.encode(svgString)); + final blob = html.Blob([bytes], 'image/svg+xml'); + final url = html.Url.createObjectUrlFromBlob(blob); + final anchor = html.AnchorElement(href: url) + ..setAttribute('download', sanitizedName) + ..click(); + html.Url.revokeObjectUrl(url); + return 'success'; + } else { + // Desktop: Use file_selector + const XTypeGroup typeGroup = XTypeGroup( + label: 'SVG Images', + extensions: ['svg'], + mimeTypes: ['image/svg+xml'], + ); + + final String? path = await fileSelector.getSavePath( + acceptedTypeGroups: [typeGroup], + suggestedName: sanitizedName, + ); + + if (path == null) { + return 'Save operation cancelled'; + } + + // Ensure the selected path ends with .svg + final String savePath = + path.toLowerCase().endsWith('.svg') ? path : '$path.svg'; + + final XFile file = XFile.fromData( + Uint8List.fromList(utf8.encode(svgString)), + mimeType: 'image/svg+xml', + name: savePath.split('/').last, + ); + + await file.saveTo(savePath); + return 'success'; } - - final XFile file = XFile.fromData( - Uint8List.fromList(utf8.encode(svgString)), - mimeType: 'image/svg+xml', - name: path.split('/').last, - path: path, - ); - - await file.saveTo(path); - return 'success'; } catch (e) { return e.toString(); } @@ -126,13 +182,9 @@ class FileServices { } Future selectImages() async { - // For Linux, you can specify the MIME types or extensions - // final fileSelector = FileSelectorPlatform.instance; const XTypeGroup typeGroup = XTypeGroup( label: 'Images', - mimeTypes: ['image/*'], // All image types - // Alternatively, you can specify extensions: - // extensions: ['jpg', 'jpeg', 'png', 'gif', 'webp'], + mimeTypes: ['image/*'], ); try { @@ -141,8 +193,6 @@ class FileServices { if (file != null) { print('Selected file: ${file.path}'); - // You can now read the file or display the image - // For example, with Image.file(File(file.path)) } return file; } catch (e) { @@ -152,7 +202,6 @@ class FileServices { } Future importJsonFiles() async { - // final fileSelector = FileSelectorPlatform.instance; const XTypeGroup typeGroup = XTypeGroup( label: 'JSON', mimeTypes: ['application/json'], @@ -171,4 +220,4 @@ class FileServices { return null; } } -} +} \ No newline at end of file diff --git a/lib/core/services/platform_file_service.dart b/lib/core/services/platform_file_service.dart index b4dc37d..e10ff18 100644 --- a/lib/core/services/platform_file_service.dart +++ b/lib/core/services/platform_file_service.dart @@ -1,47 +1,39 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; -import 'dart:async'; - import 'package:flutter/foundation.dart'; import 'package:flutter_document_picker/flutter_document_picker.dart'; +import 'package:universal_html/html.dart' as html; class PlatformFileService { static Future?> pickJSONFile() async { try { if (kIsWeb) { - // For web platform, we'll use a custom approach - // This requires the 'universal_html' package - return _pickFileWeb(); + return await _pickFileWeb(); } else { - // For non-web platforms - return _pickFileNative(); + return await _pickFileNative(); } } catch (e) { print("Error picking file: $e"); return null; } } - + static Future?> _pickFileNative() async { try { - // Use flutter_document_picker which has better platform compatibility final path = await FlutterDocumentPicker.openDocument( params: FlutterDocumentPickerParams( allowedFileExtensions: ['json'], - invalidFileNameSymbols: ['/'] + invalidFileNameSymbols: ['/'], ), ); - + if (path == null) return null; - - // Get file name from path + final fileName = path.split('/').last; - - // Read file content final File file = File(path); final bytes = await file.readAsBytes(); - + return { 'name': fileName, 'bytes': bytes, @@ -51,14 +43,34 @@ class PlatformFileService { return null; } } - + static Future?> _pickFileWeb() async { - // Implementation for web platforms would go here - // For simplicity, we'll just return a placeholder message - // A real implementation would use HTML FileReader API - throw Exception("Web file picking not implemented in this version. Please use a desktop app for file import."); + try { + final input = html.FileUploadInputElement()..accept = '.json'; + input.click(); + + await input.onChange.first; + final files = input.files; + if (files == null || files.isEmpty) return null; + + final file = files[0]; + final reader = html.FileReader(); + reader.readAsArrayBuffer(file); + + await reader.onLoad.first; + final bytes = Uint8List.fromList(reader.result as List); + final fileName = file.name; + + return { + 'name': fileName, + 'bytes': bytes, + }; + } catch (e) { + print("Web file picking error: $e"); + return null; + } } - + static Future?> parseJSONFile(Uint8List bytes) async { try { final String content = utf8.decode(bytes); diff --git a/lib/providers/workspace_provider.dart b/lib/providers/workspace_provider.dart index 9029ffd..707eb87 100644 --- a/lib/providers/workspace_provider.dart +++ b/lib/providers/workspace_provider.dart @@ -432,12 +432,16 @@ class WorkspaceProvider extends StateHandler { Future exportWorkspace({required ExportType exportType}) async { try { + // Sanitize workspace name String safeName = flowManager.flowName .replaceAll(RegExp(r'[^\w\s-]'), '') .replaceAll(RegExp(r'\s+'), '_'); if (safeName.isEmpty) safeName = "workspace"; - String fileName = "${safeName}_${DateTime.now().millisecondsSinceEpoch}"; + + // Include timestamp in file name + final timestamp = DateTime.now().millisecondsSinceEpoch; + String fileName = "${safeName}_$timestamp"; String res = ""; @@ -446,8 +450,10 @@ class WorkspaceProvider extends StateHandler { final Map workspaceData = flowManager.exportFlow(); final String jsonString = JsonEncoder.withIndent(' ').convert(workspaceData); - res = await FileServices() - .exportFile(defaultName: fileName, jsonString: jsonString); + res = await FileServices().exportFile( + defaultName: fileName, + jsonString: jsonString, + ); break; case ExportType.png: @@ -459,8 +465,10 @@ class WorkspaceProvider extends StateHandler { if (byteData != null) { final Uint8List pngBytes = byteData.buffer.asUint8List(); - res = await FileServices() - .exportPNG(defaultName: fileName, pngBytes: pngBytes); + res = await FileServices().exportPNG( + defaultName: fileName, + pngBytes: pngBytes, + ); } else { throw Exception("Failed to generate PNG data"); } @@ -468,11 +476,18 @@ class WorkspaceProvider extends StateHandler { case ExportType.svg: final svgString = _generateSVG(); - res = await FileServices() - .exportSVG(defaultName: fileName, svgString: svgString); + res = await FileServices().exportSVG( + defaultName: fileName, + svgString: svgString, + ); break; } + + if (res != 'success') { + throw Exception("Export failed: $res"); + } } catch (e) { + print("Export error: $e"); rethrow; } } @@ -567,11 +582,11 @@ class WorkspaceProvider extends StateHandler { String _escapeXml(String text) { return text - .replaceAll('&', '&') - .replaceAll('<', '<') - .replaceAll('>', '>') - .replaceAll('"', '"') - .replaceAll("'", '''); + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", "'"); } Offset _getConnectionPointCoordinates(FlowNode node, ConnectionPoint point) { @@ -766,4 +781,4 @@ class WorkspaceProvider extends StateHandler { _transformationController.dispose(); super.dispose(); } -} +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 71f8210..fd8fc55 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -105,6 +105,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a + url: "https://pub.dev" + source: hosted + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -153,6 +161,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.6" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + url: "https://pub.dev" + source: hosted + version: "1.0.2" cupertino_icons: dependency: "direct main" description: @@ -441,6 +457,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + html: + dependency: transitive + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.dev" + source: hosted + version: "0.15.6" http: dependency: "direct main" description: @@ -942,6 +966,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + universal_html: + dependency: "direct main" + description: + name: universal_html + sha256: "56536254004e24d9d8cfdb7dbbf09b74cf8df96729f38a2f5c238163e3d58971" + url: "https://pub.dev" + source: hosted + version: "2.2.4" universal_io: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 0ac65c2..2b883b7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -61,6 +61,7 @@ dependencies: url: https://github.com/TeeWrath/fastforge.git ref: main go_router: ^15.1.2 + universal_html: ^2.2.4 dev_dependencies: flutter_test: From 431d704c4e944599bfa225fe646f6c1ebd76f62d Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Wed, 21 May 2025 17:46:00 +0530 Subject: [PATCH 3/8] fix: node de-selected on clicking anywhere on workspace --- lib/providers/workspace_provider.dart | 11 +- lib/screens/workspace_screens/workspace.dart | 141 ++++++++----------- 2 files changed, 64 insertions(+), 88 deletions(-) diff --git a/lib/providers/workspace_provider.dart b/lib/providers/workspace_provider.dart index 707eb87..ce082ba 100644 --- a/lib/providers/workspace_provider.dart +++ b/lib/providers/workspace_provider.dart @@ -260,6 +260,15 @@ class WorkspaceProvider extends StateHandler { } } + void deselectAllNodes() { + if (hasSelectedNode) { + _nodeList.forEach((key, node) { + node.isSelected = false; + }); + notifyListeners(); + } + } + bool displayToolbox() { if (selectedNode != null && selectedNode!.isSelected) { notifyListeners(); @@ -432,14 +441,12 @@ class WorkspaceProvider extends StateHandler { Future exportWorkspace({required ExportType exportType}) async { try { - // Sanitize workspace name String safeName = flowManager.flowName .replaceAll(RegExp(r'[^\w\s-]'), '') .replaceAll(RegExp(r'\s+'), '_'); if (safeName.isEmpty) safeName = "workspace"; - // Include timestamp in file name final timestamp = DateTime.now().millisecondsSinceEpoch; String fileName = "${safeName}_$timestamp"; diff --git a/lib/screens/workspace_screens/workspace.dart b/lib/screens/workspace_screens/workspace.dart index 1b61175..0e8962a 100644 --- a/lib/screens/workspace_screens/workspace.dart +++ b/lib/screens/workspace_screens/workspace.dart @@ -25,8 +25,6 @@ class Workspace extends StatefulWidget { } class _WorkspaceState extends State { - // bool _isPanning = false; - @override void initState() { super.initState(); @@ -48,48 +46,38 @@ class _WorkspaceState extends State { final screenSize = MediaQuery.of(context).size; // Calculate the initial offset to center the view - // Canvas size is 100000x100000, so center is (50000, 50000) - // Adjust the offset to center it relative to the screen size final double centerX = (canvasDimension / 2) - (screenSize.width / 2); final double centerY = (canvasDimension / 2) - (screenSize.height / 2); // Set the initial transformation matrix to center the view Matrix4 matrix = Matrix4.identity() - ..translate(-centerX, - -centerY); // Negative because we move the canvas opposite to center it + ..translate(-centerX, -centerY); workspaceProvider.transformationController.value = matrix; // Sync initial state with provider workspaceProvider.updatePosition(Offset(-centerX, -centerY)); - workspaceProvider.updateScale(1.0); // Default scale + workspaceProvider.updateScale(1.0); workspaceProvider.updateFlowManager(); workspaceProvider.setInitialize(true); } - // Connect the transformation controller to the workspace provider void _syncWithProvider() { final workspaceProvider = Provider.of(context, listen: false); - // Extract matrix values final Matrix4 matrix = workspaceProvider.transformationController.value; - // Extract scale (using proper mathematical approach to extract scale) final double scaleX = math.sqrt( matrix.getColumn(0)[0] * matrix.getColumn(0)[0] + matrix.getColumn(0)[1] * matrix.getColumn(0)[1]); - // Extract translation final Offset offset = Offset(matrix.getTranslation().x, matrix.getTranslation().y); - // Update provider values workspaceProvider.updateScale(scaleX); workspaceProvider.updatePosition(offset); - - // Update flow manager to persist zoom/pan state workspaceProvider.updateFlowManager(); } @@ -105,7 +93,6 @@ class _WorkspaceState extends State { ); } - // bool _isPanning = workProvider.isPanning; return Scaffold( appBar: PreferredSize( preferredSize: const Size.fromHeight(80), @@ -204,27 +191,22 @@ class _WorkspaceState extends State { backgroundColor: white, body: Stack( children: [ - // The infinite canvas RepaintBoundary( key: workProvider.repaintBoundaryKey, child: InteractiveViewer( transformationController: workProvider.transformationController, - minScale: 0.1, // Allow zoom out to 10% + minScale: 0.1, maxScale: 5.0, - constrained: - false, // This is critical - don't constrain the canvas - boundaryMargin: - EdgeInsets.all(double.infinity), // Allow infinite panning + constrained: false, + boundaryMargin: EdgeInsets.all(double.infinity), onInteractionStart: (details) { workProvider.updatePanning(true); }, onInteractionUpdate: (details) { - // Update provider with current scale and position for node dragging calculations final Matrix4 matrix = workProvider.transformationController.value; - // Extract scale from the transformation matrixF final scaleX = math.sqrt( matrix.getColumn(0)[0] * matrix.getColumn(0)[0] + matrix.getColumn(0)[1] * matrix.getColumn(0)[1]); @@ -236,70 +218,64 @@ class _WorkspaceState extends State { workProvider.updatePosition(translation); }, onInteractionEnd: (details) { - // Sync final state with provider _syncWithProvider(); workProvider.updatePanning(false); }, - child: SizedBox( - // Huge size for effectively infinite canvas - width: canvasDimension, - height: canvasDimension, - child: Stack( - children: [ - // Background grid for better visual orientation - Positioned.fill( - child: CustomPaint( - painter: GridPainter(), - ), - ), - - // Draw connections - ...workProvider.connections.map((connection) { - return CustomPaint( - size: Size.infinite, - painter: LinePainter( - start: workProvider - .nodeList[connection.sourceNodeId]!.position, - end: workProvider - .nodeList[connection.targetNodeId]!.position, - sourceNodeId: connection.sourceNodeId, - startPoint: connection.sourcePoint, - targetNodeId: connection.targetNodeId, - endPoint: connection.targetPoint, - scale: workProvider.scale, - connection: connection, - ), - ); - }), - - // Draw nodes - ...workProvider.nodeList.entries.map((entry) { - var id = entry.key; - var node = entry.value; - return Positioned( - left: node.position.dx, - top: node.position.dy, - child: Node( - id: id, - type: node.type, - onResize: (Size newSize) => - workProvider.onResize(id, newSize), - onDrag: (offset) => - workProvider.dragNode(id, offset), - // position: node.position, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + workProvider.deselectAllNodes(); + }, + child: SizedBox( + width: canvasDimension, + height: canvasDimension, + child: Stack( + children: [ + Positioned.fill( + child: CustomPaint( + painter: GridPainter(), ), - ); - }), - ], + ), + ...workProvider.connections.map((connection) { + return CustomPaint( + size: Size.infinite, + painter: LinePainter( + start: workProvider + .nodeList[connection.sourceNodeId]!.position, + end: workProvider + .nodeList[connection.targetNodeId]!.position, + sourceNodeId: connection.sourceNodeId, + startPoint: connection.sourcePoint, + targetNodeId: connection.targetNodeId, + endPoint: connection.targetPoint, + scale: workProvider.scale, + connection: connection, + ), + ); + }), + ...workProvider.nodeList.entries.map((entry) { + var id = entry.key; + var node = entry.value; + return Positioned( + left: node.position.dx, + top: node.position.dy, + child: Node( + id: id, + type: node.type, + onResize: (Size newSize) => + workProvider.onResize(id, newSize), + onDrag: (offset) => + workProvider.dragNode(id, offset), + ), + ); + }), + ], + ), ), ), ), ), - - // UI elements that should stay fixed regardless of zoom/pan FloatingDrawer(flowId: widget.flowId), - - // Toolbar and node editing tools Positioned( top: 20, right: 20, @@ -322,8 +298,6 @@ class _WorkspaceState extends State { ], ), ), - - // Zoom indicator Positioned( right: 24, bottom: 24, @@ -335,15 +309,10 @@ class _WorkspaceState extends State { border: Border.all(color: textColor, width: 1), ), child: Builder(builder: (context) { - // Get the current matrix final matrix = workProvider.transformationController.value; - - // Extract the scale value accurately final scale = math.sqrt( matrix.getColumn(0)[0] * matrix.getColumn(0)[0] + matrix.getColumn(0)[1] * matrix.getColumn(0)[1]); - - // Display accurate percentage return Text( "${(scale * 100).toInt()}%", style: TextStyle( @@ -360,4 +329,4 @@ class _WorkspaceState extends State { }, ); } -} +} \ No newline at end of file From 465617b0e5265a8fb3d5ce701924c69793518a85 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Tue, 27 May 2025 23:22:21 +0530 Subject: [PATCH 4/8] Update README.md - bdfl declaration --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f7f21a..6ccf7f6 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,9 @@ flutter run --- ## 📜 License -This project is licensed under the **MIT License** – see the [`LICENSE`](LICENSE) file for details. +This project is licensed under the **MIT License** – see the [`LICENSE`](LICENSE) file for details. +
+I, [Subroto Banerjee](https://github.com/TeeWrath), am the Benevolent Dictator For Life (BDFL) of [Cooketh Flow](https://github.com/CookethOrg/Cooketh-Flow), leading its vision and development. I welcome contributions under our MIT license to make this visual thinking tool awesome! --- From 9cf3fef278e4ba1aa21b52727b407602b3417ae4 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Tue, 27 May 2025 23:25:03 +0530 Subject: [PATCH 5/8] Update CONTRIBUTING.md - governance section --- CONTRIBUTING.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e92a634..5b849a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,9 +46,12 @@ If you find a bug or have a feature request, please [open an issue](https://gith - Follow the [Code of Conduct](CODE_OF_CONDUCT.md). - Help others by reviewing and discussing pull requests. +## Governance +[Cooketh Flow](https://github.com/CookethOrg/Cooketh-Flow) is led by [Subroto Banerjee](https://github.com/TeeWrath) as BDFL, who makes final decisions on the project’s direction. Contributors are encouraged to share ideas via GitHub Issues, but the BDFL reserves the right to guide the roadmap. + ## License By contributing, you agree that your contributions will be licensed under the same license as Cooketh Flow. --- -We appreciate your contributions! ❤️ Happy coding! \ No newline at end of file +We appreciate your contributions! ❤️ Happy coding! From 4ec0c4e42a2ae4d704750002ba19ef52a48f96c5 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Sat, 24 May 2025 19:37:15 +0530 Subject: [PATCH 6/8] .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6661eb5..b998222 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,5 @@ app.*.map.json /android/app/release /dist/ dotenv -run.sh \ No newline at end of file +run.sh +run.ps1 \ No newline at end of file From 86a9bc35b14163a92e9472b13f30ae55a82bc283 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Wed, 25 Jun 2025 19:55:23 +0530 Subject: [PATCH 7/8] app dart --- lib/app.dart | 20 +++++++++++++++++++ lib/main.dart | 21 ++------------------ lib/screens/dashboard_screens/dashboard.dart | 8 +++++--- 3 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 lib/app.dart diff --git a/lib/app.dart b/lib/app.dart new file mode 100644 index 0000000..92746c5 --- /dev/null +++ b/lib/app.dart @@ -0,0 +1,20 @@ +import 'package:cookethflow/core/routes/app_route_config.dart'; +import 'package:flutter/material.dart'; + +class MyApp extends StatefulWidget { + const MyApp({super.key}); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + Widget build(BuildContext context) { + return MaterialApp.router( + debugShowCheckedModeBanner: false, + routerConfig: AppRouteConfig.returnRouter(), + // home: const SplashScreen(), + ); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 379eb2f..63c59b5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,4 @@ +import 'package:cookethflow/app.dart'; import 'package:cookethflow/core/routes/app_route_config.dart'; import 'package:flutter/material.dart'; import 'package:cookethflow/core/services/supabase_service.dart'; @@ -68,22 +69,4 @@ Future main() async { ], child: const MyApp(), )); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - @override - Widget build(BuildContext context) { - return MaterialApp.router( - debugShowCheckedModeBanner: false, - routerConfig: AppRouteConfig.returnRouter(), - // home: const SplashScreen(), - ); - } -} +} \ No newline at end of file diff --git a/lib/screens/dashboard_screens/dashboard.dart b/lib/screens/dashboard_screens/dashboard.dart index 0ae76f3..73968bb 100644 --- a/lib/screens/dashboard_screens/dashboard.dart +++ b/lib/screens/dashboard_screens/dashboard.dart @@ -90,9 +90,11 @@ class Dashboard extends StatelessWidget { workspaceProvider .initializeWorkspace(flowId); - context.go('${RoutesPath.workspace}/:$flowId'); - // .then((_) => - // flowProvider.refreshFlowList()); + context.go( + '${RoutesPath.workspace}/:$flowId'); + flowProvider.refreshFlowList(); + // .then((_) => + // flowProvider.refreshFlowList()); }, ); } From 24d5990052dafad78b1c937e5d0a54b76b5315b1 Mon Sep 17 00:00:00 2001 From: Subroto Banerjee Date: Fri, 27 Jun 2025 22:27:01 +0530 Subject: [PATCH 8/8] something --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b998222..02315c0 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,6 @@ app.*.map.json /dist/ dotenv run.sh -run.ps1 \ No newline at end of file +run.ps1 +run-release.sh +run-release.ps1 \ No newline at end of file