mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
306 lines
11 KiB
Dart
306 lines
11 KiB
Dart
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/community_list_view.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<SpaceManagementPage> {
|
|
// Store created spaces
|
|
List<SpaceData> spaces = [];
|
|
List<Connection> connections = [];
|
|
|
|
// Track whether to show the community list view or community structure
|
|
bool showCommunityStructure = false;
|
|
|
|
// API instance
|
|
final CommunitySpaceManagementApi _api = CommunitySpaceManagementApi();
|
|
|
|
// Data structure to store community and associated spaces
|
|
Map<String, List<SpaceModel>> 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<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) {
|
|
context.read<SpaceManagementBloc>().add(
|
|
LoadCommunityAndSpacesEvent(), // Re-fetch or perform community-specific actions
|
|
);
|
|
},
|
|
),
|
|
SizedBox(width: 45),
|
|
showCommunityStructure
|
|
? _buildCommunityStructureArea(context, screenSize)
|
|
: CommunityListViewWidget(
|
|
communities: communities,
|
|
),
|
|
],
|
|
),
|
|
_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});
|
|
}
|