mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
Fixed space layout
This commit is contained in:
@ -1,8 +1,5 @@
|
||||
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';
|
||||
@ -10,16 +7,12 @@ 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/model/space_data_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/community_structure_widget.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/widgets/gradient_canvas_border_widget.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/widgets/loaded_space_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';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
|
||||
class SpaceManagementPage extends StatefulWidget {
|
||||
const SpaceManagementPage({super.key});
|
||||
@ -34,12 +27,8 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
||||
Map<String, List<SpaceModel>> communitySpaces = {};
|
||||
double canvasWidth = 1000;
|
||||
double canvasHeight = 1000;
|
||||
|
||||
final List<NodeData> nodes = [
|
||||
NodeData(id: 'Node 1', position: Offset(100, 100)),
|
||||
NodeData(id: 'Node 2', position: Offset(300, 300)),
|
||||
NodeData(id: 'Node 3', position: Offset(500, 500)),
|
||||
];
|
||||
List<SpaceData> spaces = [];
|
||||
List<Connection> connections = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -48,7 +37,6 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size screenSize = MediaQuery.of(context).size;
|
||||
return BlocProvider(
|
||||
create: (context) => SpaceManagementBloc(CommunitySpaceManagementApi())
|
||||
..add(LoadCommunityAndSpacesEvent()),
|
||||
@ -61,7 +49,15 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
||||
if (state is SpaceManagementLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is SpaceManagementLoaded) {
|
||||
return _buildLoadedState(context, screenSize, state.communities);
|
||||
return LoadedSpaceView(
|
||||
communities: state.communities,
|
||||
selectedCommunity: selectedCommunity,
|
||||
onCommunitySelected: (community) {
|
||||
setState(() {
|
||||
selectedCommunity = community;
|
||||
});
|
||||
},
|
||||
);
|
||||
} else if (state is SpaceManagementError) {
|
||||
return Center(child: Text('Error: ${state.errorMessage}'));
|
||||
}
|
||||
@ -72,7 +68,7 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
||||
}
|
||||
|
||||
Widget _buildLoadedState(
|
||||
BuildContext context, Size screenSize, List<CommunityModel> communities) {
|
||||
BuildContext context, List<CommunityModel> communities) {
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
@ -82,285 +78,15 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
||||
communities: communities,
|
||||
onCommunitySelected: (community) {
|
||||
setState(() {
|
||||
selectedCommunity = community; // Set the selected community
|
||||
selectedCommunity = community;
|
||||
});
|
||||
},
|
||||
),
|
||||
_buildCommunityStructureArea(context, screenSize)
|
||||
CommunityStructureArea(selectedCommunity: selectedCommunity),
|
||||
],
|
||||
),
|
||||
const GradientCanvasBorderWidget()
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCommunityStructureArea(BuildContext context, Size screenSize) {
|
||||
return Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
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: 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: InteractiveViewer(
|
||||
boundaryMargin: EdgeInsets.all(500), // Adjusted for smoother panning
|
||||
minScale: 0.5,
|
||||
maxScale: 3.0,
|
||||
constrained: false,
|
||||
child: Container(
|
||||
width: canvasWidth,
|
||||
height: canvasHeight,
|
||||
child: Stack(
|
||||
children: [
|
||||
// Draw connections between nodes
|
||||
for (int i = 0; i < nodes.length - 1; i++)
|
||||
CustomPaint(
|
||||
painter:
|
||||
EdgePainter(nodes[i].position, nodes[i + 1].position),
|
||||
),
|
||||
// Render each node and make it draggable
|
||||
for (var node in nodes)
|
||||
Positioned(
|
||||
left: node.position.dx,
|
||||
top: node.position.dy,
|
||||
child: DraggableNode(
|
||||
data: node,
|
||||
onAddNode: (direction) => _addNode(node, direction),
|
||||
onPositionChanged: (newPosition) {
|
||||
_updateNodePosition(node, newPosition);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
))
|
||||
]),
|
||||
));
|
||||
}
|
||||
|
||||
void _updateNodePosition(NodeData 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;
|
||||
print("Canvas width expanded to $canvasWidth");
|
||||
}
|
||||
|
||||
// Expand canvas downward when node approaches the bottom edge
|
||||
if (node.position.dy >= canvasHeight - 200) {
|
||||
canvasHeight += 200;
|
||||
print("Canvas height expanded to $canvasHeight");
|
||||
}
|
||||
|
||||
// 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 nodes) {
|
||||
n.position = Offset(n.position.dx + shiftAmount, n.position.dy);
|
||||
}
|
||||
|
||||
print("Canvas expanded to the left. New width: $canvasWidth");
|
||||
}
|
||||
|
||||
// Prevent nodes from going out of bounds on top edge
|
||||
if (node.position.dy < 0) {
|
||||
node.position = Offset(node.position.dx, 0);
|
||||
}
|
||||
|
||||
// Log the current canvas size for debugging
|
||||
print(
|
||||
"Current canvas size: width = $canvasWidth, height = $canvasHeight");
|
||||
});
|
||||
}
|
||||
|
||||
void _addNode(NodeData parent, String direction) {
|
||||
Offset newPosition;
|
||||
switch (direction) {
|
||||
case "right":
|
||||
newPosition = parent.position + Offset(200, 0);
|
||||
break;
|
||||
case "left":
|
||||
newPosition = parent.position - Offset(200, 0);
|
||||
break;
|
||||
case "bottom":
|
||||
newPosition = parent.position + Offset(0, 200);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
nodes
|
||||
.add(NodeData(id: 'Node ${nodes.length + 1}', position: newPosition));
|
||||
|
||||
// Expand the canvas if necessary
|
||||
if (newPosition.dx >= canvasWidth - 200) canvasWidth += 200;
|
||||
if (newPosition.dy >= canvasHeight - 200) canvasHeight += 200;
|
||||
if (newPosition.dx < 0) canvasWidth += 200;
|
||||
if (newPosition.dy < 0) canvasHeight += 200;
|
||||
|
||||
print("New node added in direction $direction at $newPosition");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class NodeData {
|
||||
String id;
|
||||
Offset position;
|
||||
|
||||
NodeData({required this.id, required this.position});
|
||||
}
|
||||
|
||||
class DraggableNode extends StatefulWidget {
|
||||
final NodeData data;
|
||||
final ValueChanged<Offset> onPositionChanged;
|
||||
final ValueChanged<String>
|
||||
onAddNode; // Callback for adding a node in a specific direction
|
||||
|
||||
DraggableNode({
|
||||
required this.data,
|
||||
required this.onPositionChanged,
|
||||
required this.onAddNode,
|
||||
});
|
||||
|
||||
@override
|
||||
_DraggableNodeState createState() => _DraggableNodeState();
|
||||
}
|
||||
|
||||
class _DraggableNodeState extends State<DraggableNode> {
|
||||
bool isHovered = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
onEnter: (_) => setState(() => isHovered = true),
|
||||
onExit: (_) => setState(() => isHovered = false),
|
||||
child: GestureDetector(
|
||||
onPanUpdate: (details) {
|
||||
final newPosition = widget.data.position + details.delta;
|
||||
widget.onPositionChanged(newPosition);
|
||||
},
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
// Main node container
|
||||
Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
width: 150,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.5),
|
||||
spreadRadius: 2,
|
||||
blurRadius: 5,
|
||||
offset: const Offset(0, 3), // shadow position
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Text(
|
||||
widget.data.id,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
if (isHovered) ...[
|
||||
// Add icon on the right
|
||||
Positioned(
|
||||
right: -20,
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.add_circle, color: Colors.green, size: 20),
|
||||
onPressed: () => widget.onAddNode("right"),
|
||||
),
|
||||
),
|
||||
// Add icon on the left
|
||||
Positioned(
|
||||
left: -20,
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.add_circle, color: Colors.green, size: 20),
|
||||
onPressed: () => widget.onAddNode("left"),
|
||||
),
|
||||
),
|
||||
// Add icon on the bottom
|
||||
Positioned(
|
||||
bottom: -20,
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.add_circle, color: Colors.green, size: 20),
|
||||
onPressed: () => widget.onAddNode("bottom"),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EdgePainter extends CustomPainter {
|
||||
final Offset start;
|
||||
final Offset end;
|
||||
|
||||
EdgePainter(this.start, this.end);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()
|
||||
..color = Colors.black
|
||||
..strokeWidth = 2.0
|
||||
..style = PaintingStyle.stroke;
|
||||
|
||||
canvas.drawLine(start, end, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) => true;
|
||||
}
|
||||
|
@ -0,0 +1,215 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/add_space_button.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/space_data_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<CommunityStructureArea> {
|
||||
double canvasWidth = 1000;
|
||||
double canvasHeight = 1000;
|
||||
List<SpaceData> spaces = [];
|
||||
List<Connection> 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: InteractiveViewer(
|
||||
boundaryMargin: EdgeInsets.all(500),
|
||||
minScale: 0.5,
|
||||
maxScale: 3.0,
|
||||
constrained: false,
|
||||
child: Container(
|
||||
width: canvasWidth,
|
||||
height: canvasHeight,
|
||||
child: spaces.isEmpty
|
||||
? Center(
|
||||
child: AddSpaceButton(
|
||||
onTap: () {
|
||||
_showCreateSpaceDialog(screenSize);
|
||||
},
|
||||
),
|
||||
)
|
||||
: 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,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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: 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),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _updateNodePosition(SpaceData 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 -
|
||||
100, // Slightly above the center vertically
|
||||
);
|
||||
|
||||
SpaceData newSpace =
|
||||
SpaceData(name: name, icon: icon, position: centerPosition);
|
||||
spaces.add(newSpace);
|
||||
|
||||
_updateNodePosition(newSpace, newSpace.position);
|
||||
|
||||
// Add connection for down-button
|
||||
if (parentIndex != null && direction != null) {
|
||||
SpaceData parentSpace = spaces[parentIndex];
|
||||
connections.add(Connection(
|
||||
startSpace: parentSpace,
|
||||
endSpace: newSpace,
|
||||
direction: direction,
|
||||
));
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _handleHoverChanged(int index, bool isHovered) {
|
||||
setState(() {
|
||||
spaces[index].isHovered = isHovered;
|
||||
});
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/model/connection_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
@ -40,14 +38,20 @@ class CurvedLinePainter extends CustomPainter {
|
||||
..quadraticBezierTo(controlPoint.dx, controlPoint.dy, end.dx, end.dy);
|
||||
canvas.drawPath(path, paint);
|
||||
} else if (connection.direction == 'right') {
|
||||
// Straight line for right connections
|
||||
start = connection.startSpace.position +
|
||||
const Offset(150, 30); // Right center
|
||||
end = connection.endSpace.position + const Offset(0, 30); // Left center
|
||||
|
||||
canvas.drawLine(start, end, paint);
|
||||
} else if (connection.direction == 'left') {
|
||||
// Straight line for left connections
|
||||
start =
|
||||
connection.startSpace.position + const Offset(0, 30); // Left center
|
||||
end = connection.endSpace.position +
|
||||
const Offset(150, 30); // Right center
|
||||
|
||||
canvas.drawLine(start, end, paint);
|
||||
}
|
||||
|
||||
// Draw small connection dots at the start and end points
|
||||
|
||||
final dotPaint = Paint()..color = ColorsManager.blackColor;
|
||||
canvas.drawCircle(start, 5, dotPaint); // Start dot
|
||||
canvas.drawCircle(end, 5, dotPaint); // End dot
|
42
lib/pages/spaces_management/widgets/loaded_space_widget.dart
Normal file
42
lib/pages/spaces_management/widgets/loaded_space_widget.dart
Normal file
@ -0,0 +1,42 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/model/community_model.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/widgets/community_structure_widget.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';
|
||||
|
||||
class LoadedSpaceView extends StatefulWidget {
|
||||
final List<CommunityModel> communities;
|
||||
final CommunityModel? selectedCommunity;
|
||||
final ValueChanged<CommunityModel> onCommunitySelected;
|
||||
|
||||
const LoadedSpaceView({
|
||||
Key? key,
|
||||
required this.communities,
|
||||
this.selectedCommunity,
|
||||
required this.onCommunitySelected,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_LoadedStateViewState createState() => _LoadedStateViewState();
|
||||
}
|
||||
|
||||
class _LoadedStateViewState extends State<LoadedSpaceView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SidebarWidget(
|
||||
communities: widget.communities,
|
||||
onCommunitySelected: widget.onCommunitySelected,
|
||||
),
|
||||
CommunityStructureArea(selectedCommunity: widget.selectedCommunity),
|
||||
],
|
||||
),
|
||||
const GradientCanvasBorderWidget(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@ class PlusButtonWidget extends StatelessWidget {
|
||||
final int index;
|
||||
final String direction;
|
||||
final Offset offset;
|
||||
final Size screenSize;
|
||||
final Function(int index, Offset newPosition, String direction) onButtonTap;
|
||||
|
||||
const PlusButtonWidget({
|
||||
@ -13,7 +12,6 @@ class PlusButtonWidget extends StatelessWidget {
|
||||
required this.index,
|
||||
required this.direction,
|
||||
required this.offset,
|
||||
required this.screenSize,
|
||||
required this.onButtonTap,
|
||||
});
|
||||
|
||||
|
@ -6,18 +6,18 @@ class SpaceCardWidget extends StatelessWidget {
|
||||
final Size screenSize;
|
||||
final Offset position;
|
||||
final bool isHovered;
|
||||
final Function(int index, Offset delta) onPanUpdate;
|
||||
final Function(int index, bool isHovered) onHoverChanged;
|
||||
final Function(int index, Offset newPosition, String direction) onButtonTap;
|
||||
final Widget Function(int index) buildSpaceContainer;
|
||||
final ValueChanged<Offset> onPositionChanged;
|
||||
|
||||
const SpaceCardWidget({
|
||||
super.key,
|
||||
required this.index,
|
||||
required this.onPositionChanged,
|
||||
required this.screenSize,
|
||||
required this.position,
|
||||
required this.isHovered,
|
||||
required this.onPanUpdate,
|
||||
required this.onHoverChanged,
|
||||
required this.onButtonTap,
|
||||
required this.buildSpaceContainer,
|
||||
@ -29,7 +29,8 @@ class SpaceCardWidget extends StatelessWidget {
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onPanUpdate: (details) {
|
||||
// Call the provided callback to update the position
|
||||
onPanUpdate(index, details.delta);
|
||||
final newPosition = position + details.delta;
|
||||
onPositionChanged(newPosition);
|
||||
},
|
||||
child: MouseRegion(
|
||||
onEnter: (_) {
|
||||
@ -41,7 +42,8 @@ class SpaceCardWidget extends StatelessWidget {
|
||||
onHoverChanged(index, false);
|
||||
},
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none, // Allow hovering elements to be displayed outside the boundary
|
||||
clipBehavior: Clip
|
||||
.none, // Allow hovering elements to be displayed outside the boundary
|
||||
children: [
|
||||
buildSpaceContainer(index), // Build the space container
|
||||
if (isHovered) ...[
|
||||
@ -49,21 +51,18 @@ class SpaceCardWidget extends StatelessWidget {
|
||||
index: index,
|
||||
direction: 'left',
|
||||
offset: const Offset(-21, 20),
|
||||
screenSize: screenSize,
|
||||
onButtonTap: onButtonTap,
|
||||
),
|
||||
PlusButtonWidget(
|
||||
index: index,
|
||||
direction: 'right',
|
||||
offset: const Offset(140, 20),
|
||||
screenSize: screenSize,
|
||||
onButtonTap: onButtonTap,
|
||||
),
|
||||
PlusButtonWidget(
|
||||
index: index,
|
||||
direction: 'down',
|
||||
offset: const Offset(63, 50),
|
||||
screenSize: screenSize,
|
||||
onButtonTap: onButtonTap,
|
||||
),
|
||||
],
|
||||
|
@ -19,7 +19,8 @@ class SpaceWidget extends StatelessWidget {
|
||||
top: position.dy,
|
||||
child: GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
child:
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
@ -41,6 +42,7 @@ class SpaceWidget extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user