import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/common/buttons/add_space_button.dart'; import 'package:syncrow_web/pages/spaces_management/bloc/space_management_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/bloc/space_management_event.dart'; import 'package:syncrow_web/pages/spaces_management/bloc/space_management_state.dart'; import 'package:syncrow_web/pages/spaces_management/model/community_model.dart'; import 'package:syncrow_web/pages/spaces_management/model/space_model.dart'; import 'package:syncrow_web/pages/spaces_management/view/curved_line_painter.dart'; import 'package:syncrow_web/pages/spaces_management/view/dialogs/create_space_dialog.dart'; import 'package:syncrow_web/pages/spaces_management/widgets/sidebar_widget.dart'; import 'package:syncrow_web/pages/spaces_management/widgets/space_card_widget.dart'; import 'package:syncrow_web/pages/spaces_management/widgets/space_container_widget.dart'; import 'package:syncrow_web/services/space_mana_api.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart'; class SpaceManagementPage extends StatefulWidget { @override SpaceManagementPageState createState() => SpaceManagementPageState(); } class SpaceManagementPageState extends State { // Store created spaces List spaces = []; List connections = []; // API instance final CommunitySpaceManagementApi _api = CommunitySpaceManagementApi(); // Data structure to store community and associated spaces Map> communitySpaces = {}; @override void initState() { super.initState(); } @override Widget build(BuildContext context) { Size screenSize = MediaQuery.of(context).size; return BlocProvider( create: (context) => SpaceManagementBloc(CommunitySpaceManagementApi()) ..add(LoadCommunityAndSpacesEvent()), child: WebScaffold( appBarTitle: Text( 'Space Management', style: Theme.of(context).textTheme.headlineLarge, ), enableMenuSideba: false, scaffoldBody: BlocBuilder( builder: (context, state) { if (state is SpaceManagementLoading) { return const Center(child: CircularProgressIndicator()); } else if (state is SpaceManagementLoaded) { return _buildLoadedState(context, screenSize, state.communities); } else if (state is SpaceManagementError) { return Center(child: Text('Error: ${state.errorMessage}')); } return Container(); }, ), ), ); } Widget _buildLoadedState( BuildContext context, Size screenSize, List communities) { return Stack( clipBehavior: Clip.none, children: [ Row( children: [ SidebarWidget( communities: communities, onCommunitySelected: (community) { context.read().add( LoadCommunityAndSpacesEvent(), // Re-fetch or perform community-specific actions ); }, ), _buildCommunityStructureArea(context, screenSize), ], ), _buildGradientBorder(), ], ); } Widget _buildCommunityStructureArea(BuildContext context, Size screenSize) { return Expanded( child: Container( decoration: const BoxDecoration( color: ColorsManager.whiteColors, border: Border( left: BorderSide( color: ColorsManager.whiteColors, width: 1.0), // Light left border to match ), ), // Background color for canvas child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ 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, // Subtle shadow spreadRadius: 0, // No spread blurRadius: 8, // Softer shadow edges offset: Offset(0, 4), // Shadow only on the bottom ), ], ), child: Text( 'Community Structure', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, ), ), ), // Use Expanded to ensure InteractiveViewer takes the available space Flexible( child: InteractiveViewer( boundaryMargin: const EdgeInsets.all(500), // Adjusted to 500 minScale: 0.5, // Minimum zoom scale maxScale: 2.5, // Maximum zoom scale panEnabled: true, // Enable panning scaleEnabled: true, // Enable zooming child: Container( width: 2000, // Large canvas height: 2000, // Large canvas color: ColorsManager.transparentColor, // Transparent background child: Stack( clipBehavior: Clip.none, children: [ // Draw lines using a CustomPaint widget CustomPaint( size: Size(2000, 2000), // Explicit canvas size painter: CurvedLinePainter(connections), ), Center( child: spaces.isEmpty ? AddSpaceButton( onTap: () { _showCreateSpaceDialog(screenSize); }, ) : Stack( children: spaces .asMap() .entries .map((entry) => SpaceCardWidget( index: entry.key, screenSize: screenSize, position: spaces[entry.key].position, isHovered: spaces[entry.key].isHovered, onPanUpdate: (int index, Offset delta) { setState(() { spaces[index].position += delta; }); }, onHoverChanged: (int index, bool isHovered) { setState(() { spaces[index].isHovered = isHovered; }); }, onButtonTap: (int index, Offset newPosition, String direction) { _showCreateSpaceDialog( screenSize, position: spaces[index].position + newPosition, parentIndex: index, direction: direction, ); }, buildSpaceContainer: (int index) { return SpaceContainerWidget( index: index, icon: spaces[index].icon, name: spaces[index].name, ); }, )) .toList(), ), ), ], ), ), ), ), ], ), ), ); } Widget _buildGradientBorder() { return Positioned( top: 0, bottom: 0, left: 300, width: 8, child: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ ColorsManager.semiTransparentBlackColor.withOpacity(0.1), ColorsManager.transparentColor, ], ), ), ), ); } 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 - 100, // Slightly above the center vertically ); SpaceData newSpace = SpaceData(name: name, icon: icon, position: centerPosition); spaces.add(newSpace); // Add connection for down-button if (parentIndex != null && direction != null) { connections.add(Connection( startSpace: spaces[parentIndex], endSpace: newSpace, direction: direction, )); } }); }, ); }, ); } } // Function to open the Create Space dialog // Model for storing space information class SpaceData { final String name; final String icon; Offset position; bool isHovered; SpaceData({ required this.name, required this.icon, required this.position, this.isHovered = false, }); } // Class for connection lines between spaces class Connection { final SpaceData startSpace; final SpaceData endSpace; final String direction; Connection( {required this.startSpace, required this.endSpace, required this.direction}); }