mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
space widget
This commit is contained in:
@ -1,14 +1,19 @@
|
||||
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/view/sidebar_widget.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/view/space_card_widget.dart';
|
||||
import 'package:syncrow_web/pages/spaces_management/view/space_container_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 {
|
||||
@override
|
||||
@ -29,213 +34,207 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadCommunityAndSpacesData();
|
||||
}
|
||||
|
||||
// Function to load all communities and their respective spaces
|
||||
void _loadCommunityAndSpacesData() async {
|
||||
try {
|
||||
// Fetch all communities
|
||||
List<CommunityModel> communities = await _api.fetchCommunities();
|
||||
|
||||
for (CommunityModel community in communities) {
|
||||
// Fetch spaces hierarchy for each community
|
||||
List<SpaceModel> spaces = await _api.getSpaceHierarchy(community.uuid);
|
||||
|
||||
// Store the result in the communitySpaces map
|
||||
community.spaces = spaces;
|
||||
}
|
||||
|
||||
// Update the state to reflect loaded data
|
||||
setState(() {
|
||||
// Optionally, you can initialize something here based on the loaded data
|
||||
});
|
||||
} catch (e) {
|
||||
debugPrint('Error loading communities and spaces: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void _handleCommunitySelection(String community) {
|
||||
// Handle community selection here
|
||||
print("Selected Community: $community");
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size screenSize = MediaQuery.of(context).size;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: ColorsManager.whiteColors,
|
||||
appBar: AppBar(
|
||||
title: const Text('Space Management'),
|
||||
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.communitySpaces);
|
||||
} else if (state is SpaceManagementError) {
|
||||
return Center(child: Text('Error: ${state.errorMessage}'));
|
||||
}
|
||||
return Container();
|
||||
},
|
||||
),
|
||||
),
|
||||
body: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
// Sidebar for navigation and community list
|
||||
SidebarWidget(
|
||||
communitySpaces: communitySpaces, // Pass communitySpaces here
|
||||
onCommunitySelected: _handleCommunitySelection,
|
||||
),
|
||||
// Right Side: Community Structure Area
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: ColorsManager.whiteColors,
|
||||
border: Border(
|
||||
left: BorderSide(
|
||||
color: ColorsManager.whiteColors,
|
||||
width: 1.0), // Light left border to match
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLoadedState(BuildContext context, Size screenSize,
|
||||
Map<String, List<SpaceModel>> communitySpaces) {
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
SidebarWidget(
|
||||
communitySpaces: communitySpaces,
|
||||
onCommunitySelected: (community) {
|
||||
context.read<SpaceManagementBloc>().add(
|
||||
LoadCommunityAndSpacesEvent(), // Re-fetch or perform community-specific actions
|
||||
);
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: _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
|
||||
),
|
||||
// Background color for canvas
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
],
|
||||
),
|
||||
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: [
|
||||
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,
|
||||
),
|
||||
),
|
||||
// Draw lines using a CustomPaint widget
|
||||
CustomPaint(
|
||||
size: Size(2000, 2000), // Explicit canvas size
|
||||
painter: CurvedLinePainter(connections),
|
||||
),
|
||||
// Use Expanded to ensure InteractiveViewer takes the available space
|
||||
Expanded(
|
||||
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);
|
||||
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;
|
||||
});
|
||||
},
|
||||
)
|
||||
: 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(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
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,
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 300, // Align with the sidebar's width
|
||||
width: 8, // Width of the gradient border
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.centerLeft,
|
||||
end: Alignment.centerRight,
|
||||
colors: [
|
||||
ColorsManager.semiTransparentBlackColor
|
||||
.withOpacity(0.1), // Light gray
|
||||
ColorsManager.transparentColor, // Transparent fade
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Function to open the Create Space dialog
|
||||
void _showCreateSpaceDialog(Size screenSize,
|
||||
{Offset? position, int? parentIndex, String? direction}) {
|
||||
showDialog(
|
||||
@ -272,6 +271,8 @@ class SpaceManagementPageState extends State<SpaceManagementPage> {
|
||||
}
|
||||
}
|
||||
|
||||
// Function to open the Create Space dialog
|
||||
|
||||
// Model for storing space information
|
||||
class SpaceData {
|
||||
final String name;
|
||||
@ -298,4 +299,3 @@ class Connection {
|
||||
required this.endSpace,
|
||||
required this.direction});
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user