import 'package:flutter/material.dart'; import 'package:syncrow_web/pages/common/buttons/add_space_button.dart'; import 'package:syncrow_web/pages/spaces_management/model/space_model.dart'; import 'package:syncrow_web/pages/spaces_management/view/dialogs/create_space_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/widgets/curved_line_painter.dart'; import 'package:syncrow_web/pages/spaces_management/widgets/space_card_widget.dart'; import 'package:syncrow_web/pages/spaces_management/model/community_model.dart'; import 'package:syncrow_web/pages/spaces_management/model/connection_model.dart'; import 'package:syncrow_web/pages/spaces_management/widgets/space_container_widget.dart'; import 'package:syncrow_web/utils/color_manager.dart'; class CommunityStructureArea extends StatefulWidget { final CommunityModel? selectedCommunity; CommunityStructureArea({this.selectedCommunity}); @override _CommunityStructureAreaState createState() => _CommunityStructureAreaState(); } class _CommunityStructureAreaState extends State { double canvasWidth = 1000; double canvasHeight = 1000; List spaces = []; List connections = []; @override Widget build(BuildContext context) { Size screenSize = MediaQuery.of(context).size; return Expanded( child: Container( decoration: const BoxDecoration( border: Border( left: BorderSide(color: ColorsManager.whiteColors, width: 1.0), ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(), Flexible( child: Stack( children: [ if (spaces.isNotEmpty) InteractiveViewer( boundaryMargin: EdgeInsets.all(500), minScale: 0.5, maxScale: 3.0, constrained: false, child: Container( width: canvasWidth, height: canvasHeight, child: Stack( children: [ for (var connection in connections) CustomPaint( painter: CurvedLinePainter([connection])), for (var entry in spaces.asMap().entries) Positioned( left: entry.value.position.dx, top: entry.value.position.dy, child: SpaceCardWidget( index: entry.key, onButtonTap: (int index, Offset newPosition, String direction) { _showCreateSpaceDialog( screenSize, position: spaces[index].position + newPosition, parentIndex: index, direction: direction, ); }, position: entry.value.position, isHovered: entry.value.isHovered, screenSize: screenSize, onHoverChanged: _handleHoverChanged, onPositionChanged: (newPosition) { _updateNodePosition(entry.value, newPosition); }, buildSpaceContainer: (int index) { return SpaceContainerWidget( index: index, icon: spaces[index].icon ?? '', name: spaces[index].name, ); }, ), ), ], ), ), ), if (spaces.isEmpty) Center( child: AddSpaceButton( onTap: () { _showCreateSpaceDialog(screenSize); }, ), ), ], )), ], ), ), ); } Widget _buildHeader() { return Container( padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 27.0), width: double.infinity, decoration: BoxDecoration( color: ColorsManager.whiteColors, boxShadow: [ BoxShadow( color: ColorsManager.shadowBlackColor, spreadRadius: 0, blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Community Structure', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold), ), if (widget.selectedCommunity != null) Text( widget.selectedCommunity!.name, style: const TextStyle( fontSize: 16, color: ColorsManager.blackColor), ), ], ), // Show "Save" button only if there are spaces if (spaces.isNotEmpty && widget.selectedCommunity != null ) ElevatedButton.icon( onPressed: () { _saveSpaces(); }, icon: const Icon(Icons.save, size: 18), label: const Text("Save"), style: ElevatedButton.styleFrom( backgroundColor: ColorsManager.whiteColors, foregroundColor: Colors.black, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), side: BorderSide(color: Colors.grey.shade300), elevation: 0, ), ), ], ), ); } void _updateNodePosition(SpaceModel node, Offset newPosition) { setState(() { node.position = newPosition; // Expand canvas to the right when node approaches the right edge if (node.position.dx >= canvasWidth - 200) { canvasWidth += 200; } // Expand canvas downward when node approaches the bottom edge if (node.position.dy >= canvasHeight - 200) { canvasHeight += 200; } // Expand canvas to the left when node approaches the left edge if (node.position.dx <= 200) { double shiftAmount = 200; canvasWidth += shiftAmount; // Shift all nodes to the right by shiftAmount for (var n in spaces) { n.position = Offset(n.position.dx + shiftAmount, n.position.dy); } } // Prevent nodes from going out of bounds on top edge if (node.position.dy < 0) { node.position = Offset(node.position.dx, 0); } }); } void _showCreateSpaceDialog(Size screenSize, {Offset? position, int? parentIndex, String? direction}) { showDialog( context: context, builder: (BuildContext context) { return CreateSpaceDialog( onCreateSpace: (String name, String icon) { setState(() { // Set the first space in the center or use passed position Offset centerPosition = position ?? Offset( screenSize.width / 2 - 75, // Center horizontally screenSize.height / 2 - 50, // Slightly above the center vertically ); SpaceModel newSpace = SpaceModel(name: name, icon: icon, position: centerPosition, isPrivate: false, children: []); spaces.add(newSpace); _updateNodePosition(newSpace, newSpace.position); // Add connection for down-button if (parentIndex != null && direction != null) { SpaceModel parentSpace = spaces[parentIndex]; connections.add(Connection( startSpace: parentSpace, endSpace: newSpace, direction: direction, )); } }); }, ); }, ); } void _handleHoverChanged(int index, bool isHovered) { setState(() { spaces[index].isHovered = isHovered; }); } void _saveSpaces() { // Implement your save functionality here print("Spaces saved: ${spaces.length}"); } }