added space model link to space dialog

This commit is contained in:
hannathkadher
2025-01-11 15:42:35 +04:00
parent e70df16de3
commit 8aa493a15e
12 changed files with 502 additions and 285 deletions

View File

@ -17,6 +17,7 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/dialogs/c
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/curved_line_painter.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_card_widget.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/space_container_widget.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class CommunityStructureArea extends StatefulWidget {
@ -26,6 +27,8 @@ class CommunityStructureArea extends StatefulWidget {
final ValueChanged<SpaceModel?>? onSpaceSelected;
final List<CommunityModel> communities;
final List<SpaceModel> spaces;
final List<SpaceTemplateModel>? spaceModels;
CommunityStructureArea({
this.selectedCommunity,
@ -34,6 +37,7 @@ class CommunityStructureArea extends StatefulWidget {
this.products,
required this.spaces,
this.onSpaceSelected,
this.spaceModels,
});
@override
@ -49,9 +53,11 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
bool isEditingName = false;
late TransformationController _transformationController;
@override
void initState() {
super.initState();
print("sxdsf ${widget.spaceModels}");
spaces = widget.spaces.isNotEmpty ? flattenSpaces(widget.spaces) : [];
connections =
widget.spaces.isNotEmpty ? createConnections(widget.spaces) : [];
@ -284,6 +290,7 @@ class _CommunityStructureAreaState extends State<CommunityStructureArea> {
builder: (BuildContext context) {
return CreateSpaceDialog(
products: widget.products,
spaceModels: widget.spaceModels,
parentSpace: parentIndex != null ? spaces[parentIndex] : null,
onCreateSpace: (String name, String icon,
List<SelectedProduct> selectedProducts) {

View File

@ -7,8 +7,8 @@ import 'package:syncrow_web/pages/spaces_management/all_spaces/model/selected_pr
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/add_device_type_widget.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/dialogs/icon_selection_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/hoverable_button.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/widgets/selected_products_button_widget.dart';
import 'package:syncrow_web/pages/spaces_management/link_space_model/view/link_space_model_dialog.dart';
import 'package:syncrow_web/pages/spaces_management/space_model/models/space_template_model.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/constants/space_icon_const.dart';
@ -23,6 +23,7 @@ class CreateSpaceDialog extends StatefulWidget {
final List<SelectedProduct> selectedProducts;
final SpaceModel? parentSpace;
final SpaceModel? editSpace;
final List<SpaceTemplateModel>? spaceModels;
const CreateSpaceDialog(
{super.key,
@ -33,7 +34,8 @@ class CreateSpaceDialog extends StatefulWidget {
this.icon,
this.isEdit = false,
this.editSpace,
this.selectedProducts = const []});
this.selectedProducts = const [],
this.spaceModels});
@override
CreateSpaceDialogState createState() => CreateSpaceDialogState();
@ -59,275 +61,289 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
enteredName.isNotEmpty || nameController.text.isNotEmpty;
}
@override
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
return AlertDialog(
title: widget.isEdit
? const Text('Edit Space')
: const Text('Create New Space'),
backgroundColor: ColorsManager.whiteColors,
content: SizedBox(
width: screenWidth * 0.5, // Limit dialog width
width: screenWidth * 0.5,
child: SingleChildScrollView(
// Scrollable content to prevent overflow
child: Column(
mainAxisSize: MainAxisSize.min,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
alignment: Alignment.center,
children: [
Container(
width: screenWidth * 0.1, // Adjusted width
height: screenWidth * 0.1, // Adjusted height
decoration: const BoxDecoration(
color: ColorsManager.boxColor,
shape: BoxShape.circle,
),
),
SvgPicture.asset(
selectedIcon,
width: screenWidth * 0.04,
height: screenWidth * 0.04,
),
Positioned(
top: 6,
right: 6,
child: InkWell(
onTap: _showIconSelectionDialog,
child: Container(
width: screenWidth * 0.020,
height: screenWidth * 0.020,
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: SvgPicture.asset(
Assets.iconEdit,
width: screenWidth * 0.06,
height: screenWidth * 0.06,
),
),
),
),
],
),
const SizedBox(width: 16),
Expanded(
// Ensure the text field expands responsively
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
// crossAxisAlignment: CrossAxisAlignment.center,
children: [
Stack(
alignment: Alignment.center,
children: [
TextField(
controller: nameController,
onChanged: (value) {
enteredName = value.trim();
setState(() {
isNameFieldExist = false;
isOkButtonEnabled = false;
isNameFieldInvalid = value.isEmpty;
if (!isNameFieldInvalid) {
if (_isNameConflict(value)) {
isNameFieldExist = true;
isOkButtonEnabled = false;
} else {
isNameFieldExist = false;
isOkButtonEnabled = true;
}
}
});
},
style: const TextStyle(color: Colors.black),
decoration: InputDecoration(
hintText: 'Please enter the name',
hintStyle: const TextStyle(
fontSize: 14,
color: ColorsManager.lightGrayColor,
fontWeight: FontWeight.w400,
),
filled: true,
fillColor: ColorsManager.boxColor,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: isNameFieldInvalid || isNameFieldExist
? ColorsManager.red
: ColorsManager.boxColor,
width: 1.5,
Container(
width: screenWidth * 0.1,
height: screenWidth * 0.1,
decoration: const BoxDecoration(
color: ColorsManager.boxColor,
shape: BoxShape.circle,
),
),
SvgPicture.asset(
selectedIcon,
width: screenWidth * 0.04,
height: screenWidth * 0.04,
),
Positioned(
top: 20,
right: 20,
child: InkWell(
onTap: _showIconSelectionDialog,
child: Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(
color: ColorsManager.boxColor,
width: 1.5,
child: SvgPicture.asset(
Assets.iconEdit,
width: 16,
height: 16,
),
),
),
),
if (isNameFieldInvalid)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'*Space name should not be empty.',
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(color: ColorsManager.red),
),
),
if (isNameFieldExist)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'*Name already exist',
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(color: ColorsManager.red),
),
),
const SizedBox(height: 16),
DefaultButton(
onPressed: () {},
backgroundColor: ColorsManager.textFieldGreyColor,
foregroundColor: Colors.black,
borderColor: ColorsManager.neutralGray,
borderRadius: 16.0,
padding: 10.0, // Reduced padding for smaller size
child: Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
Assets.addIcon,
width: screenWidth *
0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
const SizedBox(width: 3),
Flexible(
child: Text(
'Link a space model',
overflow: TextOverflow
.ellipsis, // Prevent overflow
style: Theme.of(context)
.textTheme
.bodyMedium,
),
),
],
),
)),
const SizedBox(height: 30),
DefaultButton(
onPressed: () {},
backgroundColor: ColorsManager.textFieldGreyColor,
foregroundColor: Colors.black,
borderColor: ColorsManager.neutralGray,
borderRadius: 16.0,
padding: 10.0, // Reduced padding for smaller size
child: Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
Assets.addIcon,
width: screenWidth *
0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
const SizedBox(width: 3),
Flexible(
child: Text(
'Create sub space',
overflow: TextOverflow
.ellipsis, // Prevent overflow
style: Theme.of(context)
.textTheme
.bodyMedium,
),
),
],
),
)),
if (selectedProducts.isNotEmpty)
SelectedProductsButtons(
products: widget.products ?? [],
selectedProducts: selectedProducts,
onProductsUpdated: (updatedProducts) {
setState(() {
selectedProducts = updatedProducts;
});
},
context: context,
)
else
DefaultButton(
onPressed: () {
showDialog(
context: context,
builder: (context) => AddDeviceWidget(
products: widget.products,
onProductsSelected: (selectedProductsMap) {
setState(() {
selectedProducts = selectedProductsMap;
});
},
),
);
},
backgroundColor: ColorsManager.textFieldGreyColor,
foregroundColor: Colors.black,
borderColor: ColorsManager.neutralGray,
borderRadius: 16.0,
padding: 10.0, // Reduced padding for smaller size
child: Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
Assets.addIcon,
width: screenWidth *
0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
const SizedBox(width: 3),
Flexible(
child: Text(
'Add devices / Assign a space model',
overflow: TextOverflow
.ellipsis, // Prevent overflow
style: Theme.of(context)
.textTheme
.bodyMedium,
),
),
],
),
)),
],
),
),
],
],
),
),
const SizedBox(width: 20),
Expanded(
flex: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: nameController,
onChanged: (value) {
enteredName = value.trim();
setState(() {
isNameFieldExist = false;
isOkButtonEnabled = false;
isNameFieldInvalid = value.isEmpty;
if (!isNameFieldInvalid) {
if (_isNameConflict(value)) {
isNameFieldExist = true;
isOkButtonEnabled = false;
} else {
isNameFieldExist = false;
isOkButtonEnabled = true;
}
}
});
},
style: const TextStyle(color: Colors.black),
decoration: InputDecoration(
hintText: 'Please enter the name',
hintStyle: const TextStyle(
fontSize: 14,
color: ColorsManager.lightGrayColor,
fontWeight: FontWeight.w400,
),
filled: true,
fillColor: ColorsManager.boxColor,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: isNameFieldInvalid || isNameFieldExist
? ColorsManager.red
: ColorsManager.boxColor,
width: 1.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(
color: ColorsManager.boxColor,
width: 1.5,
),
),
),
),
if (isNameFieldInvalid)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'*Space name should not be empty.',
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(color: ColorsManager.red),
),
),
if (isNameFieldExist)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
'*Name already exist',
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(color: ColorsManager.red),
),
),
const SizedBox(height: 10),
DefaultButton(
onPressed: () {
_showLinkSpaceModelDialog(context);
},
backgroundColor: ColorsManager.textFieldGreyColor,
foregroundColor: Colors.black,
borderColor: ColorsManager.neutralGray,
borderRadius: 16.0,
padding: 10.0, // Reduced padding for smaller size
child: Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
Assets.link,
width: screenWidth * 0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
const SizedBox(width: 3),
Flexible(
child: Text(
'Link a space model',
overflow:
TextOverflow.ellipsis, // Prevent overflow
style: Theme.of(context).textTheme.bodyMedium,
),
),
],
),
),
),
const SizedBox(height: 25),
const Row(
children: [
Expanded(
child: Divider(
color: ColorsManager.neutralGray,
thickness: 1.0,
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
'OR',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: Divider(
color: ColorsManager.neutralGray,
thickness: 1.0,
),
),
],
),
const SizedBox(height: 25),
DefaultButton(
onPressed: () {},
backgroundColor: ColorsManager.textFieldGreyColor,
foregroundColor: Colors.black,
borderColor: ColorsManager.neutralGray,
borderRadius: 16.0,
padding: 10.0, // Reduced padding for smaller size
child: Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
Assets.addIcon,
width: screenWidth * 0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
const SizedBox(width: 3),
Flexible(
child: Text(
'Create sub space',
overflow:
TextOverflow.ellipsis, // Prevent overflow
style: Theme.of(context).textTheme.bodyMedium,
),
),
],
),
),
),
const SizedBox(height: 10),
DefaultButton(
onPressed: () {
showDialog(
context: context,
builder: (context) => AddDeviceWidget(
products: widget.products,
onProductsSelected: (selectedProductsMap) {
setState(() {
selectedProducts = selectedProductsMap;
});
},
),
);
},
backgroundColor: ColorsManager.textFieldGreyColor,
foregroundColor: Colors.black,
borderColor: ColorsManager.neutralGray,
borderRadius: 16.0,
padding: 10.0, // Reduced padding for smaller size
child: Align(
alignment: Alignment.centerLeft,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.only(left: 6.0),
child: SvgPicture.asset(
Assets.addIcon,
width: screenWidth * 0.015, // Adjust icon size
height: screenWidth * 0.015,
),
),
const SizedBox(width: 3),
Flexible(
child: Text(
'Add devices',
overflow:
TextOverflow.ellipsis, // Prevent overflow
style: Theme.of(context).textTheme.bodyMedium,
),
),
],
),
),
),
],
),
),
],
),
@ -401,4 +417,22 @@ class CreateSpaceDialogState extends State<CreateSpaceDialog> {
(widget.editSpace?.children.any((child) => child.name == value) ??
false);
}
void _showLinkSpaceModelDialog(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return LinkSpaceModelDialog(
spaceModels: widget.spaceModels ?? [],
onSave: (selectedModel) {
if (selectedModel != null) {
print('Selected Model: ${selectedModel.modelName}');
} else {
print('No model selected');
}
},
);
},
);
}
}

View File

@ -11,12 +11,13 @@ import 'package:syncrow_web/pages/spaces_management/space_model/models/space_tem
import 'package:syncrow_web/pages/spaces_management/space_model/view/space_model_page.dart';
import 'package:syncrow_web/services/space_model_mang_api.dart';
class LoadedSpaceView extends StatefulWidget {
class LoadedSpaceView extends StatelessWidget {
final List<CommunityModel> communities;
final CommunityModel? selectedCommunity;
final SpaceModel? selectedSpace;
final List<ProductModel>? products;
final List<SpaceTemplateModel>? spaceModels;
final bool shouldNavigateToSpaceModelPage;
const LoadedSpaceView({
super.key,
@ -25,17 +26,11 @@ class LoadedSpaceView extends StatefulWidget {
this.selectedSpace,
this.products,
this.spaceModels,
required this.shouldNavigateToSpaceModelPage
});
@override
_LoadedStateViewState createState() => _LoadedStateViewState();
}
class _LoadedStateViewState extends State<LoadedSpaceView> {
@override
Widget build(BuildContext context) {
final bool hasSpaceModels =
widget.spaceModels != null && widget.spaceModels!.isNotEmpty;
return Stack(
clipBehavior: Clip.none,
@ -43,29 +38,29 @@ class _LoadedStateViewState extends State<LoadedSpaceView> {
Row(
children: [
SidebarWidget(
communities: widget.communities,
selectedSpaceUuid: widget.selectedSpace?.uuid ??
widget.selectedCommunity?.uuid ??
'',
communities: communities,
selectedSpaceUuid:
selectedSpace?.uuid ?? selectedCommunity?.uuid ?? '',
),
hasSpaceModels
shouldNavigateToSpaceModelPage
? Expanded(
child: BlocProvider(
create: (context) => SpaceModelBloc(
api: SpaceModelManagementApi(),
initialSpaceModels: widget.spaceModels ?? [],
initialSpaceModels: spaceModels ?? [],
),
child: SpaceModelPage(
products: widget.products,
products: products,
),
),
)
: CommunityStructureArea(
selectedCommunity: widget.selectedCommunity,
selectedSpace: widget.selectedSpace,
spaces: widget.selectedCommunity?.spaces ?? [],
products: widget.products,
communities: widget.communities,
selectedCommunity: selectedCommunity,
selectedSpace: selectedSpace,
spaces: selectedCommunity?.spaces ?? [],
products: products,
communities: communities,
spaceModels: spaceModels,
),
],
),