Fixed space layout

This commit is contained in:
hannathkadher
2024-11-15 00:38:14 +04:00
parent eacee98de2
commit de57e0f21d
7 changed files with 292 additions and 306 deletions

View File

@ -1,8 +1,5 @@
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.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_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/bloc/space_management_event.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/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/connection_model.dart';
import 'package:syncrow_web/pages/spaces_management/model/space_data_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/model/space_model.dart';
import 'package:syncrow_web/pages/spaces_management/view/curved_line_painter.dart'; import 'package:syncrow_web/pages/spaces_management/widgets/community_structure_widget.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/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/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/services/space_mana_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/web_layout/web_scaffold.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart';
import 'package:fl_chart/fl_chart.dart';
class SpaceManagementPage extends StatefulWidget { class SpaceManagementPage extends StatefulWidget {
const SpaceManagementPage({super.key}); const SpaceManagementPage({super.key});
@ -34,12 +27,8 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
Map<String, List<SpaceModel>> communitySpaces = {}; Map<String, List<SpaceModel>> communitySpaces = {};
double canvasWidth = 1000; double canvasWidth = 1000;
double canvasHeight = 1000; double canvasHeight = 1000;
List<SpaceData> spaces = [];
final List<NodeData> nodes = [ List<Connection> connections = [];
NodeData(id: 'Node 1', position: Offset(100, 100)),
NodeData(id: 'Node 2', position: Offset(300, 300)),
NodeData(id: 'Node 3', position: Offset(500, 500)),
];
@override @override
void initState() { void initState() {
@ -48,7 +37,6 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Size screenSize = MediaQuery.of(context).size;
return BlocProvider( return BlocProvider(
create: (context) => SpaceManagementBloc(CommunitySpaceManagementApi()) create: (context) => SpaceManagementBloc(CommunitySpaceManagementApi())
..add(LoadCommunityAndSpacesEvent()), ..add(LoadCommunityAndSpacesEvent()),
@ -61,7 +49,15 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
if (state is SpaceManagementLoading) { if (state is SpaceManagementLoading) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} else if (state is SpaceManagementLoaded) { } 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) { } else if (state is SpaceManagementError) {
return Center(child: Text('Error: ${state.errorMessage}')); return Center(child: Text('Error: ${state.errorMessage}'));
} }
@ -72,7 +68,7 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
} }
Widget _buildLoadedState( Widget _buildLoadedState(
BuildContext context, Size screenSize, List<CommunityModel> communities) { BuildContext context, List<CommunityModel> communities) {
return Stack( return Stack(
clipBehavior: Clip.none, clipBehavior: Clip.none,
children: [ children: [
@ -82,285 +78,15 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
communities: communities, communities: communities,
onCommunitySelected: (community) { onCommunitySelected: (community) {
setState(() { setState(() {
selectedCommunity = community; // Set the selected community selectedCommunity = community;
}); });
}, },
), ),
_buildCommunityStructureArea(context, screenSize) CommunityStructureArea(selectedCommunity: selectedCommunity),
], ],
), ),
const GradientCanvasBorderWidget() 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;
} }

View File

@ -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;
});
}
}

View File

@ -1,5 +1,3 @@
import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/spaces_management/model/connection_model.dart'; import 'package:syncrow_web/pages/spaces_management/model/connection_model.dart';
import 'package:syncrow_web/utils/color_manager.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); ..quadraticBezierTo(controlPoint.dx, controlPoint.dy, end.dx, end.dy);
canvas.drawPath(path, paint); canvas.drawPath(path, paint);
} else if (connection.direction == 'right') { } 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); canvas.drawLine(start, end, paint);
} else if (connection.direction == 'left') { } 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); canvas.drawLine(start, end, paint);
} }
// Draw small connection dots at the start and end points
final dotPaint = Paint()..color = ColorsManager.blackColor; final dotPaint = Paint()..color = ColorsManager.blackColor;
canvas.drawCircle(start, 5, dotPaint); // Start dot canvas.drawCircle(start, 5, dotPaint); // Start dot
canvas.drawCircle(end, 5, dotPaint); // End dot canvas.drawCircle(end, 5, dotPaint); // End dot

View 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(),
],
);
}
}

View File

@ -5,7 +5,6 @@ class PlusButtonWidget extends StatelessWidget {
final int index; final int index;
final String direction; final String direction;
final Offset offset; final Offset offset;
final Size screenSize;
final Function(int index, Offset newPosition, String direction) onButtonTap; final Function(int index, Offset newPosition, String direction) onButtonTap;
const PlusButtonWidget({ const PlusButtonWidget({
@ -13,7 +12,6 @@ class PlusButtonWidget extends StatelessWidget {
required this.index, required this.index,
required this.direction, required this.direction,
required this.offset, required this.offset,
required this.screenSize,
required this.onButtonTap, required this.onButtonTap,
}); });

View File

@ -6,18 +6,18 @@ class SpaceCardWidget extends StatelessWidget {
final Size screenSize; final Size screenSize;
final Offset position; final Offset position;
final bool isHovered; final bool isHovered;
final Function(int index, Offset delta) onPanUpdate;
final Function(int index, bool isHovered) onHoverChanged; final Function(int index, bool isHovered) onHoverChanged;
final Function(int index, Offset newPosition, String direction) onButtonTap; final Function(int index, Offset newPosition, String direction) onButtonTap;
final Widget Function(int index) buildSpaceContainer; final Widget Function(int index) buildSpaceContainer;
final ValueChanged<Offset> onPositionChanged;
const SpaceCardWidget({ const SpaceCardWidget({
super.key, super.key,
required this.index, required this.index,
required this.onPositionChanged,
required this.screenSize, required this.screenSize,
required this.position, required this.position,
required this.isHovered, required this.isHovered,
required this.onPanUpdate,
required this.onHoverChanged, required this.onHoverChanged,
required this.onButtonTap, required this.onButtonTap,
required this.buildSpaceContainer, required this.buildSpaceContainer,
@ -29,7 +29,8 @@ class SpaceCardWidget extends StatelessWidget {
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onPanUpdate: (details) { onPanUpdate: (details) {
// Call the provided callback to update the position // Call the provided callback to update the position
onPanUpdate(index, details.delta); final newPosition = position + details.delta;
onPositionChanged(newPosition);
}, },
child: MouseRegion( child: MouseRegion(
onEnter: (_) { onEnter: (_) {
@ -41,7 +42,8 @@ class SpaceCardWidget extends StatelessWidget {
onHoverChanged(index, false); onHoverChanged(index, false);
}, },
child: Stack( 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: [ children: [
buildSpaceContainer(index), // Build the space container buildSpaceContainer(index), // Build the space container
if (isHovered) ...[ if (isHovered) ...[
@ -49,21 +51,18 @@ class SpaceCardWidget extends StatelessWidget {
index: index, index: index,
direction: 'left', direction: 'left',
offset: const Offset(-21, 20), offset: const Offset(-21, 20),
screenSize: screenSize,
onButtonTap: onButtonTap, onButtonTap: onButtonTap,
), ),
PlusButtonWidget( PlusButtonWidget(
index: index, index: index,
direction: 'right', direction: 'right',
offset: const Offset(140, 20), offset: const Offset(140, 20),
screenSize: screenSize,
onButtonTap: onButtonTap, onButtonTap: onButtonTap,
), ),
PlusButtonWidget( PlusButtonWidget(
index: index, index: index,
direction: 'down', direction: 'down',
offset: const Offset(63, 50), offset: const Offset(63, 50),
screenSize: screenSize,
onButtonTap: onButtonTap, onButtonTap: onButtonTap,
), ),
], ],

View File

@ -19,7 +19,8 @@ class SpaceWidget extends StatelessWidget {
top: position.dy, top: position.dy,
child: GestureDetector( child: GestureDetector(
onTap: onTap, onTap: onTap,
child: Container( child:
Container(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
@ -41,6 +42,7 @@ class SpaceWidget extends StatelessWidget {
], ],
), ),
), ),
), ),
); );
} }