Files
syncrow-web/lib/pages/spaces_management/view/spaces_management_page.dart

329 lines
12 KiB
Dart

import 'dart:math';
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/gradient_canvas_border_widget.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 {
const SpaceManagementPage({super.key});
@override
SpaceManagementPageState createState() => SpaceManagementPageState();
}
class SpaceManagementPageState extends State<SpaceManagementPage> {
// Store created spaces
List<SpaceData> spaces = [];
List<Connection> connections = [];
double canvasWidth = 1000; // Initial canvas width
double canvasHeight = 1000; // Initial canvas height
// Track whether to show the community list view or community structure
// Selected community
CommunityModel? selectedCommunity;
// API instance
final CommunitySpaceManagementApi _api = CommunitySpaceManagementApi();
// Data structure to store community and associated spaces
Map<String, List<SpaceModel>> communitySpaces = {};
@override
void initState() {
super.initState();
}
void updateCanvasSize() {
print("test");
double maxX = 0;
double maxY = 0;
// Calculate the maximum X and Y positions of all spaces
for (var space in spaces) {
print(
"Space Position: ${space.position.dx}, ${space.position.dy}"); // Log the position of each space
maxX = max(maxX, space.position.dx + 150); // Add width of space
maxY = max(maxY, space.position.dy + 60); // Add height of space
}
// Add padding (but avoid adding arbitrary amounts like 1000)
double newWidth =
max(maxX + 500, canvasWidth); // Use max to ensure the canvas only grows
double newHeight = max(maxY + 500, canvasHeight);
// Set the new canvas size dynamically
setState(() {
canvasWidth = newWidth;
canvasHeight = newHeight;
});
// Log the updated canvas size for debugging
print("Max X: $maxX, Max Y: $maxY");
print("Updated canvas size: $canvasWidth x $canvasHeight");
}
@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,
),
enableMenuSidebar: false,
scaffoldBody: BlocBuilder<SpaceManagementBloc, SpaceManagementState>(
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<CommunityModel> communities) {
return Stack(
clipBehavior: Clip.none,
children: [
Row(
children: [
SidebarWidget(
communities: communities,
onCommunitySelected: (community) {
setState(() {
selectedCommunity = community; // Set the selected community
});
},
),
_buildCommunityStructureArea(context, screenSize)
],
),
const GradientCanvasBorderWidget()
],
);
}
Widget _buildCommunityStructureArea(BuildContext context, Size screenSize) {
return Expanded(
child: Container(
decoration: const BoxDecoration(
color: ColorsManager.blackColor,
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.blackColor,
boxShadow: [
BoxShadow(
color: ColorsManager.shadowBlackColor, // Subtle shadow
spreadRadius: 0, // No spread
blurRadius: 8, // Softer shadow edges
offset: const Offset(0, 4), // Shadow only on the bottom
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Community Structure',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
if (selectedCommunity != null) ...[
Text(
selectedCommunity!.name, // Show community name
style: const TextStyle(
fontSize: 16,
color: ColorsManager.blackColor, // Slightly muted color
),
),
]
],
),
),
// Use Expanded to ensure InteractiveViewer takes the available space
Flexible(
child: InteractiveViewer(
boundaryMargin: const EdgeInsets.all(20000), // Adjusted to 500
minScale: 0.5, // Minimum zoom scale
maxScale: 5.5, // Maximum zoom scale
panEnabled: true, // Enable panning
scaleEnabled: true, // Enable zooming
child: Container(
width: canvasWidth, // Large width for free movement
height: canvasHeight, // Large height for free movement
color: ColorsManager.blue1, // Transparent background
child: spaces.isEmpty
? Center(
child: AddSpaceButton(
onTap: () {
_showCreateSpaceDialog(screenSize);
},
),
)
: Stack(
clipBehavior: Clip.none,
children: [
CustomPaint(
size: const Size(4000, 4000),
painter: CurvedLinePainter(connections),
),
...spaces.asMap().entries.map((entry) {
final space = entry.value;
return Positioned(
left: space.position.dx,
top: space.position.dy,
child: SpaceCardWidget(
index: entry.key,
screenSize: screenSize,
position: space.position,
isHovered: space.isHovered,
onPanUpdate: (int index, Offset delta) {
debugPrint("Check it works");
setState(() {
spaces[index].position += delta;
});
updateCanvasSize();
},
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,
);
},
),
);
}),
],
)),
),
),
],
),
),
);
}
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);
updateCanvasSize();
// 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});
}